《SQL必知必会》读后随笔

举报
云端小宅女 发表于 2021/07/26 15:08:35 2021/07/26
【摘要】 提示:结束 SQL 语句多条SQL语句必须以分号(;)分隔。多数DBMS不需要在单条SQL语句后加分号,但也有DBMS可能必须在单条SQL语句后加上分号。当然,如果愿意可以总是加上分号。事实上,即使不一定需要,加上分号也肯定没有坏处提示:SQL 语句和大小写请注意,SQL语句不区分大小写,因此 SELECT 与 select 是相同的。 同样,写成Select 也没有关系。许多SQL开发人员...

提示:结束 SQL 语句
多条SQL语句必须以分号(;)分隔。多数DBMS不需要在单条SQL语句后加分号,但也有DBMS可能必须在单条SQL语句后加上分号。
当然,如果愿意可以总是加上分号。事实上,即使不一定需要,加上分号也肯定没有坏处


提示:SQL 语句和大小写
请注意,SQL语句不区分大小写,因此 SELECT 与 select 是相同的。 同样,写成Select 也没有关系。许多SQL开发人员喜欢对SQL关键 字使用大写,而对列名和表名使用小写,这样做使代码更易于阅读和调试。不过,一定要认识到虽然SQL是不区分大小写的,但是表名、列名和值可能有所不同(这有赖于具体的DBMS及其如何配置)。

注意:第 0 行
第一个被检索的行是第0行,而不是第1行。因此,LIMIT 1 OFFSET 1 会检索第 2行,而不是第1行。

提示:MySQL 和 MariaDB 捷径
MySQL和MariaDB支持简化版的LIMIT 4 OFFSET 3语句,即LIMIT 3,4。 使用这个语法,逗号之前的值对应OFFSET,逗号之后的值对应LIMIT

说明:并非所有的SQL 实现都一样
我加入这一节只有一个原因,就是要说明,SQL虽然通常都有相当一致的实现,但你不能想当然地认为它总是这样。非常基本的语句往往是容易移植的,但较复杂的语句就不同了。当你针对某个问题寻找SQL解决方案时,一定要记住这一点


注意:ORDER BY 子句的位置
在指定一条 ORDER BY 子句时,应该保证它是 SELECT 语句中最后一 条子句。如果它不是最后的子句,将会出现错误消息。


提示:通过非选择列进行排序
通常,ORDER BY 子句中使用的列将是为显示而选择的列。但是,实 际上并不一定要这样,用非检索的列排序数据是完全合法的

警告:在多个列上降序排序
如果想在多个列上进行降序排序,必须对每一列指定 DESC 关键字

提示:区分大小写和排序顺序
在对文本性数据进行排序时,A 与 a 相同吗?a 位于 B 之前,还是 Z 之后?这些问题不是理论问题,其答案取决于数据库的设置方式。
在字典(dictionary)排序顺序中,A 被视为与 a 相同,这是大多数数据库管理系统的默认行为。
但是,许多DBMS允许数据库管理员在需要时改变这种行为(如果你的数据库包含大量外语字符,可能必须这样做)。
这里的关键问题是,如果确实需要改变这种排序顺序,用简单的 ORDER BY 子句可能做不到。你必须请求数据库管理员的帮助。

提示:在 WHERE 子句中使用圆括号
任何时候使用具有 AND 和 OR 操作符的 WHERE 子句,都应该使用圆括号明确地分组操作符。不要过分依赖默认求值顺序,即使它确实如你希望的那样。使用圆括号没有什么坏处,它能消除歧义

说明:Access 通配符
如果使用的是 Microsoft Access,需要使用 * 而不是 %。


说明:区分大小写
根据 DBMS的不同及其配置,搜索可以是区分大小写的。如果区分大小写,则'fish%'与 Fish bean bag toy 就不匹配。


说明:请注意后面所跟的空格
包括 Access在内的许多 DBMS都用空格来填补字段的内容。例如,如果某列有50个字符,而存储的文本为 Fish bean bag toy(17个字 符),则为填满该列需要在文本后附加33个空格。
这样做一般对数据及其使用没有影响,但是可能对上述SQL语句有负面影响。子句WHERE prod_name LIKE 'F%y'只匹配以 F 开头、以 y 结尾的 prod_name。
如果值后面跟空格,则不是以 y 结尾,所以 Fish bean bag toy 就不会检索出来。简单的解决办法是给搜索模式再增加一个%号:'F%y%' 还匹配 y 之后的字符(或空格)。更好的解决办法是用函数去掉空格


注意:请注意 NULL
通配符%看起来像是可以匹配任何东西,但有个例外,这就是 NULL。 子句 WHERE prod_name LIKE '%'不会匹配产品名称为 NULL 的行


说明:DB2 通配符
DB2不支持通配符_。


说明:Access 通配符
如果使用的是 Microsoft Access,需要使用 ? 而不是 _


说明:并不总是支持集合
与前面描述的通配符不一样,并不是所有 DBMS都支持用来创建集合的[]。只有微软的 Access 和 SQL Server 支持集合


说明:使用通配符的技巧
不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用其他操作符。 
在确实需要使用通配符时,也尽量不要把它们用在搜索模式的开始处。把通配符置于开始处,搜索起来是最慢的。 
仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据。


说明:是+还是||?
Access和 SQL Server使用 + 号。
DB2、Oracle、PostgreSQL、SQLite和 Open Office Base使用 ||


说明:TRIM 函数
大多数 DBMS都支持 RTRIM()(正如刚才所见,它去掉字符串右边的空格)、LTRIM()(去掉字符串左边的空格)以及 TRIM()(去掉字符串左右两边的空格)


注意:别名
别名的名字既可以是一个单词,也可以是一个字符串。如果是后者,字符串应该括在引号中。虽然这种做法是合法的,但不建议这么去做。多单词的名字可读性高,不过会给客户端应用带来各种问题。
因此, 别名最常见的使用是将多个单词的列名重命名为一个单词的名字


说明:导出列
别名有时也称为导出列(derived column),不管怎么叫,它们所代表的是相同的东西


提示:如何测试计算
SELECT 语句为测试、检验函数和计算提供了很好的方法。虽然 SELECT 通常用于从表中检索数据,但是省略了 FROM 子句后就是简单地访问和处理表达式,
例如
SELECT 3 * 2;将返回6
SELECT Trim(' abc '); 将返回 abc
SELECT Now();使用Now()函数返回当前日期和时间
现在你明白了,可以根据需要使用 SELECT 语句进行检验


提示:是否应该使用函数?
现在,你面临是否应该使用函数的选择。决定权在你,使用或是不使用也没有对错之分。如果你决定使用函数,应该保证做好代码注释, 以便以后你(或其他人)能确切地知道所编写的SQL代码的含义。


聚集函数(aggregate function)
对某些行运行的函数,计算并返回一个值


注意:只用于单个列
AVG()只能用来确定特定数值列的平均值,而且列名必须作为函数参 数给出。为了获得多个列的平均值,必须使用多个 AVG()函数


说明:NULL 值
AVG()函数忽略列值为 NULL 的行。


说明:NULL 值
如果指定列名,则 COUNT()函数会忽略指定列的值为空的行,但如果 COUNT()函数中用的是星号(*),则不忽略


提示:对非数值数据使用 MAX()
虽然 MAX()一般用来找出最大的数值或日期值,但许多(并非所有) DBMS 允许将它用来返回任意列中的最大值,包括返回文本列中的最大值。
在用于文本数据时,MAX()返回按该列排序后的最后一行。


说明:NULL 值
MAX()函数忽略列值为 NULL 的行


提示:对非数值数据使用 MIN()
虽然 MIN()一般用来找出最小的数值或日期值,但许多(并非所有) DBMS 允许将它用来返回任意列中的最小值,包括返回文本列中的最 小值。在用于文本数据时,MIN()返回该列排序后最前面的行


说明:NULL 值
MIN()函数忽略列值为 NULL 的行


提示:在多个列上进行计算
如本例所示,利用标准的算术操作符,所有聚集函数都可用来执行多 个列上的计算


说明:NULL 值
SUM()函数忽略列值为 NULL 的行


注意:DISTINCT 不能用于 COUNT(*)
如果指定列名,则 DISTINCT 只能用于 COUNT()。DISTINCT 不能用于 COUNT(*)。类似地,DISTINCT 必须使用列名,不能用于计算或表达式


提示:将 DISTINCT 用于 MIN()和 MAX()
虽然 DISTINCT 从技术上可用于 MIN()和 MAX(),但这样做实际上没有价值。一个列中的最小值和最大值不管是否只考虑不同值,结果都是相同的


说明:其他聚集参数
除了这里介绍的 DISTINCT 和 ALL 参数,有的DBMS还支持其他参数, 如支持对查询结果的子集进行计算的 TOP 和 TOP PERCENT。


注意:取别名
在指定别名以包含某个聚集函数的结果时,不应该使用表中实际的列名。虽然这样做也算合法,但许多 SQL实现不支持,可能会产生模糊的错误消息


注意:在使用 GROUP BY 子句前,需要知道一些重要的规定
(1)GROUP BY 子句可以包含任意数目的列,因而可以对分组进行嵌套, 更细致地进行数据分组。 
(2)如果在 GROUP BY 子句中嵌套了分组,数据将在后指定的分组上进 行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以 不能从个别的列取回数据)。 
(3)GROUP BY 子句中列出的每一列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在 SELECT 中使用表达式,则必须在 GROUP BY 子句中指定相同的表达式。不能使用别名。 
(4)大多数SQL实现不允许 GROUP BY 列带有长度可变的数据类型(如文本或备注型字段)。 
(5)除聚集计算语句外,SELECT 语句中的每一列都必须在 GROUP BY 子句中给出。 
(6)如果分组列中包含具有 NULL 值的行,则 NULL 将作为一个分组返回。 如果列中有多行 NULL 值,它们将分为一组。 
(7)GROUP BY 子句必须出现在 WHERE 子句之后,ORDER BY 子句之前


说明:HAVING 和 WHERE 的差别
这里有另一种理解方法,WHERE 在数据分组前进行过滤,HAVING 在数 据分组后进行过滤。
这是一个重要的区别,WHERE 排除的行不包括在分组中。这可能会改变计算值,从而影响 HAVING 子句中基于这些值过滤掉的分组


说明:使用 HAVING 和 WHERE
HAVING 与 WHERE 非常类似,如果不指定 GROUP BY,则大多数 DBMS 会同等对待它们。
不过,你自己要能区分这一点。使用 HAVING 时应该结合 GROUP BY 子句,而 WHERE 子句用于标准的行级过滤。


提示:不要忘记 ORDER BY
一般在使用 GROUP BY 子句时,应该也给出 ORDER BY 子句。这是保证数据正确排序的唯一方法。千万不要仅依赖 GROUP BY 排序数据


注意:只能是单列
作为子查询的 SELECT 语句只能查询单个列。企图检索多个列将返回错误


注意:完全限定列名
你已经看到了为什么要使用完全限定列名,没有具体指定就会返回错误结果,因为 DBMS会误解你的意思。有时候,由于出现冲突列名而 导致的歧义性,会引起 DBMS抛出错误信息。
例如,WHERE 或 ORDER BY 子句指定的某个列名可能会出现在多个表中。好的做法是,如果在 SELECT 语句中操作多个表,就应使用完全限定列名来避免歧义


警告:完全限定列名
就像前一课提到的,在引用的列可能出现歧义时,必须使用完全限定 列名(用一个句点分隔表名和列名)。如果引用一个没有用表名限制的 具有歧义的列名,大多数 DBMS会返回错误


注意:不要忘了 WHERE 子句
要保证所有联结都有 WHERE 子句,否则 DBMS将返回比想要的数据多得多的数据。同理,要保证 WHERE 子句的正确性。不正确的过滤条件 会导致 DBMS返回不正确的数据


提示:叉联结
有时,返回笛卡儿积的联结,也称叉联结(cross join)


注意:性能考虑
DBMS 在运行时关联指定的每个表,以处理联结。这种处理可能非常耗费资源,因此应该注意,不要联结不必要的表。联结的表越多,性能下降越厉害。


注意:Oracle 中没有 AS
Oracle不支持 AS 关键字。要在 Oracle中使用别名,可以不用 AS,简单地指定列名即可(因此,应该是 Customers C,而不是 Customers AS C)


提示:用自联结而不用子查询
自联结通常作为外部语句,用来替代从相同表中检索数据的使用子查 询语句。虽然终的结果是相同的,但许多 DBMS处理联结远比处理 子查询快得多。应该试一下两种方法,以确定哪一种的性能更好


提示:外联结的类型
要记住,总是有两种基本的外联结形式:左外联结和右外联结。它们 之间的唯一差别是所关联的表的顺序。换句话说,调整 FROM 或 WHERE 子句中表的顺序,左外联结可以转换为右外联结。因此,这两种外联 结可以互换使用,哪个方便就用哪个


提示:组合查询和多个 WHERE 条件
多数情况下,组合相同表的两个查询所完成的工作与具有多个 WHERE 子句条件的一个查询所完成的工作相同。
换句话说,任何具有多个 WHERE 子句的 SELECT 语句都可以作为一个组合查询,在下面可以看到这一点


提示:UNION 与 WHERE
这一课一开始我们说过,UNION 几乎总是完成与多个 WHERE 条件相同 的工作。UNION ALL 为 UNION 的一种形式,它完成 WHERE 子句完成 不了的工作。
如果确实需要每个条件的匹配行全部出现(包括重复行), 就必须使用 UNION ALL,而不是 WHERE。


说明:其他类型的 UNION
某些 DBMS还支持另外两种 UNION:EXCEPT(有时称为 MINUS)可用 来检索只在第一个表中存在而在第二个表中不存在的行;而 INTERSECT 可用来检索两个表中都存在的行。实际上,这些 UNION 很 少使用,因为相同的结果可利用联结得到。


提示:插入多行
INSERT 通常只插入一行。要插入多行,必须执行多个 INSERT 语句。 INSERT SELECT是个例外,它可以用一条INSERT插入多行,不管SELECT 语句返回多少行,都将被 INSERT 插入。


说明:INSERT SELECT 与 SELECT INTO
它们之间的一个重要差别是前者导出数据,而后者导入数据


提示:更快的删除
如果想从表中删除所有行,不要使用 DELETE。可使用 TRUNCATE TABLE 语句,它完成相同的工作,而速度更快(因为不记录数据的变动)


注意:性能问题
因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时需要的所有检索。如果你用多个联结和过滤创建了复杂的视图或者嵌 套了视图,性能可能会下降得很厉害。
因此,在部署使用了大量视图的应用前,应该进行测试。


说明:视图重命名
删除视图,可以使用 DROP 语句,其语法为 DROP VIEW viewname;。
覆盖(或更新)视图,必须先删除它,然后再重新创建

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。