这里主要说一下SELECT语句的基础,主要对单个表的查询,将从下面几方面做一个简单的介绍
1、SELECT语句的元素
2、谓词和运算符
3、case表达式
4、NULL值
5、同时操作
6、处理字符数据
7、处理日期和时间数据
8、查询元数据
–这篇博文主要讲这一个,下面的会在我的 其他博文文章中整理出来
SELECT语句元素
select语句的目的是对表进行查询,应用一定的逻辑处理,并返回结果
先看一段查询代码1-1
--1-1
SELECT empid,YEAR(orderdate) as order year,COUNT(*) AS numorders
FROM sales.Orders
WHERE custid = 71
GROUP BY empid,YEAR(orderdate)
HAVING COUNT(*)>1
ORDER BY empid,orderyear;
我先不着急解释上面一段代码,我们先看一下每个查询子句的处理顺序,在大多数编程语言中,代码行是按照编写的顺序来执行处理的,但是在SQL中,情况则有些不同,下面是SQL语句的处理顺序
1、FROM
2、WHERE
3、GROUP BY
4、HAVING
5、SELECT
6、ORDER BY
所以1-1中的代码执行顺序就是
FROM sales.Orders
WHERE custid = 71
GROUP BY empid,YEAR(orderdate)
HAVING COUNT(*)>1
SELECT empid,YEAR(orderdate) as orderyear,COUNT(*) AS numorders
ORDER BY empid,orderyear;
--从sales.Orders表中查询数据
--对数据进行过滤,值保留custid=71的记录
--按empid和YEAR(orderdate)分组
--返回每组数量大于1的记录
--返回每个组的empid、YEAR(orderdate)、numorders
--按照empid和orderyear升序排序
上面看了一个简单的但是涵盖整个查询过程的SQL语句,接下来详细的说一下每个阶段
1、FROM子句
FROM子句是逻辑处理的第一个阶段,这个子句指定了要查询的表名,以及对这些表进行操作的表运算符(CROSS JOIN,INNER JOIN,LEFT OUTER JOIN等)。我推荐总是使用数据库架构来限定代码的对象名称,即使你没有显示的指定架构名称,SQL也一定会隐式地解析它,但是这样就产生了一些额外的代价
FROM sales.Orders
--(sales)就是数据库架构名
2、WHERE子句
在WHERE子句中可以指定一个谓词或者逻辑表达式,从而过滤FROM阶段返回行,只有能让逻辑表达式结果为true的行,才能由WHERE阶段返回给后续的处理阶段
FROM sales.Orders
WHERE custid = 71
--只返回custid=71的记录给后续的处理阶段
这里需要注意的是,虽然where只返回让逻辑表达式结果为true的那些行,但是要时刻记住SQL是三值处理逻辑True、False、UNKONWN,在后面我会说一下NULL值得特点,以及逻辑处理NULL值得返回特点
3、GROUP BY子句
GROUP BY子句可以将前面的逻辑查询处理阶段返回的行按“组”进行组合,组合的依据是由在GROUP BY子句中指定的个元素决定,例如代码清单1-1就只用了empid和YEAR(orderdate)来进行分组,
这就意味着在WHERE阶段返回的数据中出现的每个empid和YEAR(orderdate)都是唯一的组合
FROM sales.Orders
WHERE custid = 71
GROUP BY empid,YEAR(orderdate)
如果查询中涉及到分组,那么GROUP BY 阶段之后的所有阶段的操作对象都将是组,而不是单独的行;
每个组最终表示的是查询解雇集中到的一行,这就意味着在group by阶段之后处理的子句中指定的所有表达式务必保证每个组只返回一个标量(单值)
这就意味着要对一组中的某些值进行聚合,因为聚合函数只为每个组返回一个值,所以一个元素如果不在GROUP BY 列表中出现,就只能作为聚合函数(COUNT , SUM , AVG , MAX , MIN)的输入
SELECT empid,YEAR(orderdate) as orderyear,COUNT(*) AS numorders
FROM sales.Orders
WHERE custid = 71
GROUP BY empid,YEAR(orderdate)
如果试图引用不在GROUP BY列表中出现的属性,而且也没有将其作为GROUP BY 子句之后处理的任何子句中聚合函数的输入,则SQL引擎会报错
这里要注意一点,所有的聚合函数都会忽略NULL值,只有一个例外——COUNT(*)
4、HAVING子句
HAVING子句 用于指定对组进行过滤的谓词或逻辑表达式,这与WHERE阶段对单独行进行过滤相对应,只有能让HAVING子句中的逻辑表达式返回TRUE的组,才会被返回到下一个逻辑查询阶段,逻辑处理为FALSE和UNKONWN的组将会被过滤掉
因为HAVING子句是在对行进行分组后处理的,所有可以在逻辑表达式中引用聚合函数。
FROM sales.Orders
WHERE custid = 71
GROUP BY empid,YEAR(orderdate)
HAVING COUNT(*)>1
5、SELECT子句
SELECT用于指定需要在查询返回的结果集中包含的属性(列);
SELECT列表的表达式可以直接基于正在查询的表的各个列,,也可以在此基础上做进一步的处理;
默认的目标列的名称是和原始的列名一样的,当然也可以自定列名,这里给大家说三种自定义列名的方式
AS关键字 : YEAR(orderdate) as orderyear —-推荐使用
等于符号 :YEAR(orderdate) = orderyear
空格:YEAR(orderdate) orderyear
当然,有些处理是没有基于原始表的列,这时如果不为表达式取别名的话,在查询的结果集中就不会拥有列名
在某些情况下,T-SQL允许查询返回的结果集没有列名,但是关系模型不允许
到目前为止,我们已经处理了代码清单1-1中查询的以下语句
SELECT empid,YEAR(orderdate) as order year,COUNT(*) AS numorders
FROM sales.Orders
WHERE custid = 71
GROUP BY empid,YEAR(orderdate)
HAVING COUNT(*)>1
这里要说一个值得注意的地方
SELECT语句是在FROM、WHERE、GROUP BY 以及HAVING子句处理之后处理的,这就意味着对于SELECT子句之前处理的那些子句,不能引用在SELECT语句中指定的别名
SELECT empid,YEAR(orderdate) as orderyear
FROM sales.Orders
WHERE orderyear>2006
上面的查询看似没有什么问题,但是在WHERE执行阶段还没有orderyear这个别名,所以orderyear别名在WHERE子句中是无效的,SQL引擎会报错
SELECT语句中的DISTINCT子句
这个子句很简单,就一个作用——在返回结果集之前删除重复行
SELECT DISTINCT empid,YEAR(orderdate) as orderyear
FROM sales.Orders
WHERE custid=71
SQL支持在SELECT中使用星号(*)来选择查询表中的所有列,这样就不必将他们全部显示的列举出来
SELECT * FROM Sales.Shippers
不过除了很少数的列外情况以外,在绝大多数情况下,使用星号是一种糟糕的编程习惯,还是建议你即使需要显示被查询的表的所有的列,也应该显示的指定它们
6、ORDER BY子句
ORDER BY子句用于展示数据输出时对输出的结果集进行排序,从逻辑处理顺序来看,ORDER BY是最后处理的一个子句
SELECT empid,YEAR(orderdate) as order year,COUNT(*) AS numorders
FROM sales.Orders
WHERE custid = 71
GROUP BY empid,YEAR(orderdate)
HAVING COUNT(*)>1
ORDER BY empid,orderyear;
--按照empid和orderyear来升序排列结果集
上面的ORDER BY使用了orderyear别名进行排序,这里就不用做太多解释了,因为ORDER BY是唯一一个在SELECT处理阶段后的子句
理解SQL最重要的一点就是要明白表不保证是有序的,因为表是为了代表一个集合,而集合是无序的,这就意味着,如果在查询表时不指定ORDER BY 子句,那么虽然查询可以返回一个结果集,但SQL可以自由的按照人任意的顺序对结果集进行排序
不过,如果使用ORDER BY进行排序后,查询结果将不再符合结果集的要求,带有ORDER BY子句的查询会生成一种ANSI称为游标的结果(一种非关系结果,其中的行具有固定的顺序)
ORDER BY有两种排序模式,升序(ASC)和降序(DESC),SQL引擎默认为升序
ORDER BY empid,orderyear DESC;
--按照orderyear降序排列
T-SQL支持在ORDER BY子句中指定没有在SELECT子句中出现过的元素,也就是说,排序依据的列并不一定必须要在输出返回的列中选取,
但是有一个例外的,如果SELECT指定了DISTINCT去除重复的时候,ORDER BY子句就被限定只能选取SELECT子句中指明的列
因为当指定了distinct时,一个结果行可能代表多个原始行,因此无法清楚的知道应该使用ORDER BY列表值中多个可能值得哪一个
由于篇幅的原因,上面目录中提到的内容会在我的其他博文中整理出来
期待你阅读下一篇相关博文【02单表查询】——02:TOP指定数量查询