技术开发 频道

抛开程序员思维定式,简单几步掌握SQL

    虽然没有规则说明应该用IN还是EXISTS,但有些东西可以说明:

  1、IN比EXISTS更易读

  2、EXISTS往往比IN更具表达性(即更容易表达非常复杂的SEMI JOIN)

  3、性能上没有明显差异。不过,在某些数据库上可能存在巨大的性能差异。

  因为INNER JOIN只生成那些实际上有书的作者信息,所以许多初学者可能会认为他们可以使用DISTINCT删除重复的图书,他们认为可以这样表达一个SEMI JOIN:

抛开程序员思维定式,简单几步掌握SQL

  这是非常糟糕的做法,有两个原因:

  1、它非常慢,因为数据库必须加载大量的数据到内存,只是为了删除重复的副本。

  2、它不完全正确,即使在这个简单的例子中产生正确的结果。一旦加入更多的表引用,将非常难以正确地从结果中删除重复的副本。

  ANTI JOIN

  这个关系概念恰恰与SEMI JOIN相反。可以通过在IN或EXISTS谓词中添加NOT关键字来简单地生成它。例如,我们将选择没有任何书籍的作者:

抛开程序员思维定式,简单几步掌握SQL

  关于性能,可读性和表达性的规则同样适用。 然而,当使用NOT IN时,有一个关于NULL的小警告,这有点超出本教程的范围。

  CROSS JOIN

  这将产生两个连接表引用的叉积,将第一个表引用的每个记录与第二个表引用的每个记录合并。我们之前已经看到,这可以通过FROM子句中的逗号分隔表引用来实现。在实际应用中,很少用到 CROSS JOIN,如果需要,可以这样表达:

抛开程序员思维定式,简单几步掌握SQL

  简而言之,如果JOIN是乘法,那么DIVISION就是是JOIN的逆。关系分割在SQL中很难表达。因为这是一个适用初学者的教程,所以,这里便不再赘述.

  总之,SQL的重点是表引用。连接表是相当复杂的表引用。但是在关系语言和SQL语言中有一个区别。并非所有关系连接操作都是正确的SQL连接操作。通过一些关于关系理论的实践和认知,将能够选择正确类型的JOIN,并能够将其转换为正确的SQL。

  SQL派生表就像表变量

  之前,我们了解到SQL是一个声明性语言,因此,没有变量(一些SQL衍生语言中可能会有)。但你可以写一些变量,这些变量可以称为派生表。派生表是用括号括起来的子查询。

抛开程序员思维定式,简单几步掌握SQL

  注意,一些SQL示例中需要派生表具有相关的名称(也称为别名)。

抛开程序员思维定式,简单几步掌握SQL

  当你想要规避由SQL子句逻辑排序导致的问题时,派生表是不二选择的。 例如,如果要在SELECT和WHERE子句中重用列表达式,只需写(Oracle):

抛开程序员思维定式,简单几步掌握SQL

  注意,一些数据库和SQL:1990 标准中,派生表被归为通用表语句(common table experssion)。允许用户在一个 SELECT 语句中对派生表多次重用。上面的例子(几乎)等价于下面的语句:

抛开程序员思维定式,简单几步掌握SQL

  显然,你还可以将“a”外部化为独立视图,以便更广泛地重用该派生表。

  SQL GROUP BY是针对表引用的

  让我们重新考虑我们以前的FROM子句:

抛开程序员思维定式,简单几步掌握SQL

  现在,让我们将GROUP BY子句应用到上述组合表中引用

抛开程序员思维定式,简单几步掌握SQL

  上面产生了一个有三个字段的新的表引用。如果应用GROUP BY,将减少所有后续逻辑子句的可用列数,包括SELECT。 这就是为什么select 后面的所有列中没有使用聚合函数的列,而必须出现在 group by 后面的原因了。

  请注意,其他列仍可用作聚合函数的参数:

抛开程序员思维定式,简单几步掌握SQL

  不幸的是,MySQL不遵守这个标准,并会造成混乱。总结来看,GROUP BY可以再次对表引用进行操作,将它们转换为新的形式。

  SQL中的SELECT在关系代数中称为投影

  我个人很喜欢“投影”这个术语,它用于关系代数中。在SQL中, 一旦生成表引用,就可以对其进行过滤,转换,将其投影成另一种形式。SELECT子句就像一个投影机。 表函数使用行值表达式将每个记录从先前构造的表引用转换为最终结果。

  在SELECT子句中,最后可以对列执行操作,从而创建复杂的列表达式作为记录/行的一部分。关于表达式,函数等的性质,有很多特殊的规则。最重要的是,你应该记住这些:

  1、你只能使用那些可以通过表引用得到的字段。

  2、.如果有GROUP BY子句,则只能引用该子句的列或聚合函数。

  3、没有GROUP BY子句时,可以使用窗口函数代替聚合函数。

  4、如果没有GROUP BY子句,则不能将聚合函数与非聚合函数组合。

  5、有关在聚合函数中封装常规函数的一些方法,反之亦然......

  有很多复杂的规则,这里无法全部列举出来。而在不使用GROUP BY子句的SELECT语句的投影中,不能将聚合函数与非聚合函数组合的原因是:

  1、直观地讲,没意义。

  第一直觉就是没意义(尤其是对SQL初学者而言,几乎没有任何价值)。SQL:1999介绍了GROUPING SETS,而SQL:2003引入了空分组集:GROUP BY ()。无论何时存在聚合函数,并且没有显式的GROUP BY子句,都将应用隐式的空GROUPING SET(规则编号2)。虽说这件事让我很困惑,但确实如此。

  SELECT子句可能是SQL中最复杂的子句之一,即使它看起来很简单。 其他语句的作用其实就是对表不同形式的引用 ,而SELECT子句完全转换了这些表引用,对这些表引用进行各类操作,并且过程还可逆。

  为了理解SQL,在尝试解决SELECT之前,先了解一些基本情况是重要的。虽然SELECT是语法排序中的第一个子句,但不急着第一个掌握。

  SQL DISTINCT,UNION,ORDER BY和OFFSET都很简单

  在看完复杂的SELECT语句之后,我们可以再次回到简单的事情:

  集合运算(DISTINCT和UNION)

  排序运算(ORDER BY,OFFSET .. FETCH)

  集合运算就是对“集合”进行操作,这实际上不是...表,好吧,差不多。在概念上,他们很容易理解。

抛开程序员思维定式,简单几步掌握SQL

  所有这些删除重复通常是无意义的。当你想要连接多个子查询时,你应该使用UNION ALL。

  排序不是关系特征。它是一个仅限于SQL的功能。它应用于SQL语句的双向排序和逻辑排序的结尾。使用ORDER BY和OFFSET .. FETCH是保证记录可以通过索引以可靠的方式访问的唯一方法。所有其他排序总是任意和随机的,即使它可能看起来是可再现的。

  OFFSET .. FETCH只有一个语法变体。其他变体包括MySQL和PostgreSQL的LIMIT .. OFFSET或SQL Server和Sybase的TOP...START AT。

  和每种语言一样,SQL也需要很多练习来掌握。以上10个简单的步骤将帮助你更好地了解你每天写的SQL语句。其次,从常见的错误中学习也是一个很好的办法。


0
相关文章