这些文章我很多年前就收藏在笔记里了,今天偶然拿出来重读一遍,还是收获颇多。一起分享、讨论。
本文是专门为以下读者撰写的:
1、工作中使用SQL但不太理解的人。 2、熟练使用SQL但不理解其语法和逻辑的人。 3. 想要向他人教授SQL 的人。本文重点介绍SELECT 语句的结构。完全理解SQL 的10 个简单步骤
1。 SQL 是一种声明性语言。
首先,让我们记住“声明”的概念。 SQL 语言是告诉计算机您希望从原始数据中获得什么结果,而不是告诉它如何获得结果的示例。 SQL执行引擎根据声明的数据结果检索对应的数据。
SELECTfirst_name,last_nameFROMemployeeWHEREsalary100000 上面的例子并不关心员工记录来自哪里,它只想要工资大于10W的员工。
我们从哪里学到的?
如果SQL 语言如此简单,那么是什么让人们“对SQL 感到兴奋”呢?
造成这种情况的主要原因是我们无意识地按照命令式编程思想来思考问题。这是这样的: “计算机,先运行这一步,然后运行那一步。但首先,检查条件A 和条件B 是否满足。例如,使用变量传递参数、使用循环语句、迭代和调用函数都是这个命令的一部分。”编程思维。
2. SQL 构造不按语法顺序执行。
SQL 语句具有令大多数人感到困惑的特征。即SQL语句的执行顺序与语句的语法顺序不匹配。 SQL 语句的语法顺序为:
SELECT[DISTINCT]FROMWHEREGROUP BYHAVINGUNIONORDER BY 为了便于理解,上面并未列出所有SQL 语法结构,而只是为了表明SQL 语句的语法顺序与其执行顺序完全不同。以上述说法为例。其执行顺序为:
关于FROMWHEREGROUP BYHAVINGSELECTDISTINCTUNIONORDER BY SQL 语句的执行顺序,需要记住三件事。
1、FROM是SQL语句执行的第一步,而不是SELECT。数据库执行SQL语句的第一步是将数据从硬盘加载到数据缓冲区中以便对其进行操作。 2. SELECT 在大多数语句执行完毕后执行。从技术上讲,它是在FROM 和GROUP BY 之后执行的。理解这一点非常重要。因此,SELECT 中带别名的字段不能用作WHERE 中的条件。 SELECT A.x + A.y AS z FROM A WHERE z=10 — 这里不允许使用z,因为SELECT 是最后执行的语句。如果您想重用别名z,您有两个选择。或者干脆重写z表示的表达式。
SELECT A.x + A.y AS z FROM A WHERE (A.x + A.y)=10 或者,使用派生表、通用数据表达式或视图以避免别名重用。
3. 无论是语法还是执行顺序,UNION 始终排在ORDER BY 之前。很多人认为所有UNION段都可以使用ORDER BY进行排序,但由于SQL语言标准和各个数据库的SQL实现的差异,事实并非如此。某些数据库允许您在SQL 语句中对子查询或派生表进行排序,但这并不意味着排序会保留UNION 操作后的排序顺序。 注意:并非所有数据库都以相同的方式解析SQL 语句。例如,MySQL、PostgreSQL 和SQLite 的行为与上面第二点中提到的不同。我们学到了什么?
并非所有数据库都以上述方式执行SQL,那么您会得到什么呢?
我们的教训是永远记住SQL 语句的语法顺序与其执行顺序不匹配,以避免常见错误。如果您记住SQL 语句的语法顺序和执行顺序之间的差异,您就可以轻松理解一些最常见的SQL 问题。
当然,如果一种语言的设计使得语法顺序直接反映语句执行的顺序,那么该语言对于程序员来说会更容易使用。这种编程语言级别的设计理念已经被微软应用到了LINQ语言中。
3. SQL语言的核心是表引用。
由于SQL语句的语法顺序和执行顺序的差异,很多同学认为SELECT中的字段信息才是SQL语句的核心。其实真正的症结在于对表格的引用。
根据SQL标准,FROM语句定义为:
from 子句:=FROM 表引用[ { 逗号表引用}. ] FROM 语句的“输出”是在特定维度上连接所有引用表所产生的连接表。我们慢慢分析一下:
FROM a,b 上面的FROM 语句的输出是连接表a 和表b 的连接表。如果表a有3个字段,表b有5个字段,则输出表将有8(=5+3)个字段。
这个联合表中的数据是a*b,是a和b的笛卡尔积。也就是说,a表中的所有数据必须与b表中的所有数据配对。如果a表有3条数据,b表有5条数据,则连接后的表将有15(=5*3)条数据。
FROM输出的结果经过WHERE语句的过滤,并经过GROUP BY语句的处理,形成新的输出结果。
从集合论(关系代数)的角度来看,数据库表是数据元素关系的集合,每条SQL语句都会修改一个或多个关系,从而生成新的数据元素关系((即生成一个新的数据元素关系) 。桌子)。
我们学到了什么?
在思考问题时,如果从表的角度来思考,就更容易理解SQL 语句“管道”中的数据如何变化。
4、灵活的表引用让SQL语句更加强大
灵活的表引用使SQL语句更加强大。一个简单的例子是JOIN 的使用。
严格来说,JOIN 语句不是SELECT 的一部分,而是一种特殊的表引用语句。
SQL语言标准中的表连接定义如下:
表参考:=表名称| 连接表| 考虑前面的示例。
当您运行FROM a, ba 时,您可能会得到如下连接:
a1 JOIN a2 ON a1.id=a2.id 将其应用于前面的示例,我们得到:
FROM a1 JOIN a2 ON a1.id=a2.id, b 使用逗号将连接表与另一个表连接起来并不常见,但可以做到。最终输出表包含a1+a2+b字段。
在SQL 语句中应用派生表比下面描述的表连接更强大。
我们学到了什么?
在思考问题时,从表引用的角度出发,可以帮助你理解SQL语句是如何处理数据的,也可以帮助你理解复杂的表引用的作用。
更重要的是,重要的是要了解JOIN 是用于构建连接表的关键字,而不是SELECT 语句的一部分。某些数据库允许在INSERT、UPDATE 和DELETE 上进行JOIN。
5、建议在SQL语句中使用表连接
首先我们看一下这句话。
FROM a, b 高级SQL 程序员可能会建议:连接表时避免使用逗号代替JOIN,可以使SQL 语句更易于阅读并避免一些错误。使用逗号来简化SQL 语句,请考虑以下语句:
FROM a, b, c, d, e, f, g, hWHERE a.a1=b.bxAND a.a2=c.c1AND d.d1=b.bc– 等等.使用您可以轻松检查它。 JOIN 语句的优点是: 安全。 JOIN 与正在连接的表非常接近,因此可以避免错误。
对于其他连接方式,JOIN语句可以区分外部连接和内部连接等。
我们学到了什么?
尽可能使用JOIN 连接表,并避免在FROM 之后使用逗号连接表。
6、SQL语句中的各种连接操作
SQL语句中的表连接方式基本上分为以下五种。
EQUI JOINSEMI JOINANTI JOINCROSS JOINDIVISIONEQUI JOIN 是最常见的JOIN 操作,包括两种连接方法:
内连接(或联接)
外连接(包括左、右、全外连接)
通过示例来解释差异是最简单的。
— 此表参考包括作者及其书籍。 — 每本书及其作者都有一条记录。 –不包括没有booksauthor 的作者JOIN book ON writer.id=book.author_id –该表引用包括authors和authors。他们的书——每本书及其作者都有一条记录。 — .或者没有书籍的作者有“空”记录– (“空”表示所有书籍列均为NULL)author LEFTOUTER JOIN book ON writer.id=book.author_idSEMI JOIN
SQL中有两种方式表达这种连接关系:使用IN和EXISTS。 “SEMI”在拉丁语中的意思是“一半”。此连接方法仅连接部分目标表。这意味着什么?
我们再思考一下上面的作者和标题之间的关系。让我们想象一下这种情况。不需要作者和书名的组合,只需要书名列表中的书籍作者信息。然后你可以写:
— 使用INFROMauthorWHEREauthor.id IN(SELECT book.author_id FROM book) — 使用EXISTSFROMauthorWHERE EXISTS (SELECT 1 FROM book WHERE book.author_id=author.id) 但是你必须使用IN 没有硬性规定到什么时候。如果需要使用EXISTS,则需要了解以下内容:
IN比EXISTS更具可读性,EXISTS比IN更具表现力(适合复杂语句),而且还使用INNER JOIN,所以它们之间没有性能差异(尽管有些数据库可能(差异很大)。由于可以检索到书名列表中的书籍对应的信息,初学者可以考虑使用DISTINCT去重,写一个SEMI JOIN语句,如下所示。
— 仅查找也有一本书的作者SELECT DISTINCT first_name, last_nameFROMauthorJOIN book ONauthor.id=book.author_id 这是非常糟糕的写作,原因如下:
SQL语句性能不佳是因为重复数据删除操作(DISTINCT)需要数据库重复将数据从硬盘读取到内存中。这并不完全正确。目前这可能不是问题,但随着SQL 语句变得越来越复杂,在不重复的情况下获得正确的结果变得非常困难。反连接
这种连接关系与SEMI JOIN完全相反。可以通过在IN 或EXISTS 之前添加NOT 关键字来使用此连接。例如,让我们列出标题列表中没有书籍的作者。
— 使用INFROMauthorWHEREauthor.id NOT IN (SELECT book.author_id FROM book) — 使用EXISTSFROMauthorWHERE NOT EXISTS(SELECT 1 FROM book WHEREbook.author_id=author.id) 以获得性能、可读性、演示力等特性进行评估。详细信息请参见半连接。
交叉连接
这个连接过程就是两个表连接起来的结果。第一表中的每条数据与第二表中的每条数据相对应。我们之前已经见过这种情况,但这就是在FROM 语句中使用逗号的方式。在实际应用程序中,很少使用CROSS JOIN,但一旦使用,您可以使用如下SQL 语句:
— CROSS JOIN bookDIVISION DIVISION 将所有作者和所有图书作者连接在一起,这真是一个怪胎。也就是说,如果JOIN 是乘法运算,则DIVISION 是JOIN 的逆运算。 DIVISION 关系很难用SQL 表达这是初学者指南,因此解释DIVISION 超出了其范围。
我们学到了什么?
学到了很多!再在脑子里想一想。 SQL是对表的引用,而JOIN是引用表的复杂方式。然而,SQL语言的表示和实际所需的逻辑关系之间存在差异。并不是每一个逻辑关系都能找到对应的JOIN操作,所以需要在日常生活中积累和学习更多的关系逻辑。创建未来的SQL 语句时选择适当的JOIN 操作。
7、像SQL中的变量一样派生表
之前我们了解到SQL是一种声明式语言,SQL语句不能包含变量。但是,您可以编写看起来像变量的语句。这些称为派生表。
坦率地说,所谓的派生表就是括号内的子查询。
— DERIVED TABLES FROM(SELECT * FROM writer) 请注意,您可以定义与派生表关联的名称(我们称之为别名)。
— 带有aliasFROM(SELECT * FROMauthor) 的派生表派生表可以有效避免SQL逻辑带来的问题。
示例:如果想复用使用SELECT 和WHERE 语句的查询结果,可以这样写(以Oracle 为例):
— 获取作者的名字、姓氏和年龄(以天为单位) SELECT First_name, Last_name, AgeFROM( SELECT First_name, Last_name, current_date- date_of_birth Age FROM Author)– 如果年龄超过10000 天WHEREage 10000 需要注意的事项:数据库和SQL:1990标准,派生表被分类为下一个级别的——公共表语句(公共表扩展)。这允许派生表在SELECT 语句中多次重用。
上面的示例(大约)相当于以下语句:
WITH a AS( SELECT First_name, Last_name, current_date- date_of_birth Age FROM Author)SELECT *FROM aWHERE Age 10000 当然,您也可以创建“a”的另一个视图,并在范围更广的派生表中重用它。
我们学到了什么?
总的来说,我们一再强调SQL语句是对表的引用,而不是字段的引用。要利用这一点,请毫不犹豫地使用派生表或其他更复杂的语句。
8. SQL 语句中的GROUP BY 适用于表引用。
让我们回顾一下前面的FROM 语句。
FROM a, b 然后将GROUP BY 应用于上面的语句。
GROUP BY A.x, A.y, B.z 上述语句导致对包含三个字段的新表的引用。请仔细理解这句话。当您应用GROUP BY 时,在SELECT 之后不使用聚合函数的列将出现在GROUP BY 之后。 (译者注:原文大致意思是“GROUP BY 减少了可以进行下一级逻辑操作的列数,包括SELECT 中的列。”) 其他注意,字段还可以使用聚合函数。
SELECT A.x, A.y, SUM(A.z)FROM AGROUP BY A.x, A.y 另一件值得注意的是MySQL 不符合这个标准。这无疑是非常令人困惑的。 (译者注:我并不是说MySQL没有GROUP BY功能。)但是不要让MySQL欺骗了你。 GROUP BY 更改了表的引用方式。这样您就可以使用SELECT 引用字段并使用GROUP BY 进行分组。
我们学到了什么?
GROUP BY 还可以操作表引用并将其转换为新的引用方法。
9. SQL语句SELECT本质上是一个关系映射
我个人更喜欢“映射”这个词,尤其是在关系代数中使用时。 (译者注:原词是projection,这个词有两个意思,第一个意思是预测、规划、设计;第二个意思是投影、映射。经过深思熟虑,这里我觉得用映射更直观(代表SELECT 的功能)。一旦建立了对表的引用,您就可以通过修改和转换逐渐将表映射到另一个模型。
SELECT语句可以理解为将源表中的数据按照某种逻辑转换为目标表中的数据的函数。
SELECT 语句允许您操作每个字段并通过复杂的表达式生成您需要的数据。
SELECT 语句有很多特殊规则,因此您至少应该了解以下内容:
只能使用可通过表引用检索的字段。如果您有GROUP BY 语句,则只能在GROUP BY 语句之后使用字段或聚合函数。开窗函数取代了聚合函数。如果语句中没有GROUP BY,则聚合函数不能和其他函数一起使用。有多种方法可以将常规函数封装为聚合函数。够了,我又写了一篇文章。例如,为什么我不能在SELECT 语句中同时使用常规函数和聚合函数而不使用GROUP BY(上面的第4 点)?
原因如下:
直观上,这种方法没有逻辑意义。 即使你不能直观地理解它,你也应该能够通过语法来理解它。 SQL : 1999 标准引入了GROUPING SETS,SQL:2003 标准引入了组集: GROUP BY()。如果语句具有聚合函数并且没有显式GROUP BY 语句,则会将不明确的空GROUPING SET 应用于SQL。因此,原有的逻辑排序规则被打破,映射(即SELECT)关系首先影响逻辑关系,然后影响语法关系。 (译者注:这一段原文比较难,但是很容易理解,如下:在一条同时包含聚合函数和正则函数的SQL语句中,如果没有GROUP BY进行分组,则SQL默认情况下,该语句将整个表聚合为一个组。当聚合函数对特定字段执行聚合统计时,它将引用表中的所有数据聚合为一个统计值,因此它不会将整个表聚合为一个组。目前对每条记录使用一个函数是有意义的)。 使困惑?我也是。让我们回过头来看一些更简单的事情。
我们学到了什么?
尽管SELECT 语句看起来很简单,但它可能是所有SQL 语句中最困难的部分。其他语句的作用实际上都是对表的各种形式的引用。 SELECT 语句集成这些引用,并根据逻辑规则将源表映射到目标表。另外,这个过程是可逆的,您可以清楚地看到目标表中的数据是如何获取的。
如果你想学好SQL语言,在使用SELECT语句之前你应该了解其他语句。 SELECT 是语法结构中的第一个关键字,但应该最后学习。
10. SQL语句中的一些简单关键字:DISTINCT、UNION、ORDER BY、OFFSET
了解了复杂的SELECT 之后,让我们看一些更简单的东西。
集合操作(set actions):集合操作的主要操作实际上是指对表的操作。从概念上讲,这些很容易理解。
DISTINCT 映射后删除重复数据。 UNION 连接两个子查询以消除重复。 UNION ALL 连接两个子查询而不进行重复数据删除。 EXCEPT 从第一个子查询中删除第二个子查询的结果。 INTERSECT 保留两个子查询的结果并删除排序操作。
排序操作与逻辑关系无关。这是SQL 特定的功能。排序操作不仅在SQL语句的末尾执行,而且在SQL语句执行过程的最后执行。使用ORDER BY 和OFFSET.FETCH 是确保数据有序的最有效方法。所有其他排序方法在某种程度上都是随机的,但它们产生的排序结果是可重复的。 OFFSET.SET 是一个没有统一语法的语句。例如,每个数据库都有不同的表达式,例如MySQL和PostgreSQL中的LIMIT.OFFSET,SQL Server和Sybase中的TOP.START AT。
原创文章,作者:共创,如若转载,请注明出处:https://www.sudun.com/ask/94336.html