绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
除了会排序,你对ORDER BY的用法可能一无所知!
2019-12-09 14:47:26

导读

  • 为什么只有ORDER  BY后面可以使用列别名
  • 为什么不推荐使用ORDER BY后接数字来排序
  • 为什么视图和子查询里面不能使用ORDER BY

    ……


小伙伴们在进行SQL排序时,都能很自然的使用到ORDER BY。不管是默认ASC的升序,还是DESC降序,几乎都是信手拈来。


今天给大家分享一些你可能不知道的ORDER BY用法。


一、ORDER BY返回的是游标而不是集合

SQL的理论其实是集合论,常见的类似求数据的交集、并集、差集都可以使用集合的思维来求解。


集合中的行之间没有预先定义的顺序,它只是成员的一种逻辑组合,成员之间的顺序无关紧要。


如下图,每一个括号里的内容就是一条记录,在没排序前,他们都是随机分布在集合中。


Student(ID,Name,Age)

Student集合


但是对于带有排序作用的ORDER BY子句的查询,它返回的是一个对象,其中的行按特定的顺序组织在一起,我们把这种对象称为游标。

如下图,经过对Student表的ID进行ORDER BY排序后,Student表变成了有序对象,也就是我们上面说的游标。


Student(ID,Name,Age)

Student对象




二、ORDER BY子句是能重用列别名的一步

这里涉及SQL语句的语法顺序和执行顺序了,我们常见的SQL语法顺序如下:

SELECT DISTINCT  <Top Num> <select list>
FROM [left_table]
<join_type> 
JOIN <right_table>
ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
WITH <CUBE | RollUP>
HAVING <having_condition>
ORDER BY <order_by_list> 
而数据库引擎在执行SQL语句并不是从SELECT开始执行,而是从FROM开始,具体执行顺序如下(关键字前面的数字代表SQL执行的顺序步骤):


(8)SELECT (9)DISTINCT  (11)<Top Num> <select list>
(
1)FROM [left_table]
(
3)<join_type> JOIN <right_table>
(
2)        ON <join_condition>
(
4)WHERE <where_condition>
(
5)GROUP BY <group_by_list>
(
6)WITH <CUBE | RollUP>
(
7)HAVING <having_condition>
(
10)ORDER BY <order_by_list> 


从上面可以看到SELECT在HAVING后才开始执行,这个时候SELECT后面列的别名只对后续的步骤生效,而对SELECT前面的步骤是的。所以如果你在WHERE,GROUP BY,或HAVING后面使用列的别名均会报错。


我们举例测试一下。


示例表Customers结构及数据如下:


1、WHERE后面不使用别名的情况


SELECT 
姓名 AS Name,
地址 AS Address,
城市 AS City
FROM Customers
WHERE 城市='广州'
结果如下:


2、WHERE后面使用列别名的情况
SELECT 
姓名 AS Name,
地址 AS Address,
城市 AS City
FROM Customers
WHERE City='广州'


执行结果如下:


从返回的消息中我们可以看到,重命名后的City并不能被WHERE识别,所以才会报“列名'City'”的提示。


其他关键字大家也可以使用上述方法进行测试,下面我们测试GROUP BY和HAVING后面使用列别名的情况。


3、测试GROUP BY后使用列别名
SELECT 
城市 AS City
FROM Customers
GROUP BY City


结果如下:


4、测试HAVING后使用列别名


SELECT 
城市 AS City
FROM Customers
GROUP BY 城市
HAVING COUNT(City)>1


结果如下:


5、测试ORDER BY后面使用列别名


SELECT 
姓名 AS Name,
地址 AS Address,
城市 AS City
FROM Customers
ORDER BY City


结果如下:


从上面的几个测试示例的结果中,可以得出我们的结论是正确的:ORDER BY子句是能重用列别名的一步。


三、谨慎使用ORDER BY 后面接数字的方式来进行排序

有些小伙伴为了图省事,喜欢在ORDER BY后面写数字,具体示例如下:


SELECT 
姓名 AS Name,
地址 AS Address,
城市 AS City
FROM Customers
ORDER BY 1,2,3


结果如下:

这样写的结果,针对当前的查询是正确没有问题的,ORDER BY后面的数字1,2,3分别代表SELECT后面的第1,第2,第3个字段(也就是Name,Address,City)。
可是当查询的列发生改变,忘了修改ORDER BY列表。特别是当查询语句很长时,要找到ORDER BY与SELECT列表中的哪个列相对应会非常困难。


例如


SELECT 
客户ID AS ID,
姓名 AS Name,
地址 AS Address,
城市 AS City
FROM Customers
ORDER BY 1,2,3


由于增加了一列“客户ID”,原本的题意还是对Name,Address,City排序,但是因为使用了ORDER BY加数字,排序后的结果如下:

得到的结果并不是我们想要的,所以请慎用ORDER BY加数字,尽量使用ORDER BY加列名或列别名


四、表表达式不能使用ORDER BY排序
表表达式包括视图,内联表值函数,派生表(子查询)和公用表表达式(CTE)。
例如下面的视图是的
CREATE VIEW V_Customers AS
SELECT 
客户ID AS ID,
姓名 AS Name,
地址 AS Address,
城市 AS City
FROM Customers
ORDER BY ID,Name,Address
结果如下:


这个错误是不是很熟悉?因为很多小伙伴经常喜欢在视图或子查询里面加ORDER BY,然后一执行就会报这个错。


根本原因不敢妄加断定,因为搜寻了很多文献资料也没给出一个具体的说法。

这里我猜测是因为视图,内联表值函数,派生表(子查询)和公用表表达式(CTE)等返回的结果还需要进一步的去使用,加了ORDER BY进行排序是多此一举,反而会浪费系统资源。所以数据库的开发者不希望大家使用这样不规范操作。


所以下次就不要在表表达式里添加ORDER BY了。


五、T-SQL中表表达式加了TOP可以使用ORDER BY
我们从第四点的报错信息中可以看到:在另外还指定了 TOP、OFFSET 或 FOR XML是可以使用ORDER BY的。

这又是为什么呢?

我们还是先举个栗子给大家看一下

SELECT 
客户ID AS ID,
姓名 AS Name,
地址 AS Address,
城市 AS City
FROM
(SELECT TOP 3 *
FROM Customers
ORDER BY 城市) Customers
ORDER BY ID,Name,Address


结果如下:


因为T-SQL中带有ORDER BY的表表达式加了TOP后返回的是一个没有固定顺序的表。因此,在这种情况下,ORDER BY子句只是为TOP选项定义逻辑顺序,就是下面这个逻辑子句


SELECT TOP 3 *
FROM Customers
ORDER BY 城市
结果如下:


而不保证结果集的排列顺序,因为表表达式外面至少还有一层才是我们终需要的结果集。


这里的ORDER BY只对当前的子查询生效,到了主查询是不起作用的。必须在主查询末尾继续添加一个ORDER BY子句才能对结果集生效,就像我们例子中写的那样。


除非逻辑要求,一般情况下并不推荐大家这样巧妙的避开子查询中不能使用ORDER BY的限制


以上就是有关ORDER BY的一些用法,你学会了吗?有不明白或疑问的地方,欢迎在底下留言。


觉得不错,记得转发分享给更多人,谢谢啦~



——End——

关注SQL数据库开发公众号,在后台回复关键字:资料领取,可以获取一份精心整理的技术干货。

推荐阅读

点击「阅读原文」了解SQL训练营

分享好友

点击获得分享链接,复制给好友成功购买后您可以获得2成返利哦~

SQL数据库开发
创建时间:2019-10-16 16:39:35
分享有关SQL Server,Mysql,Oracle等数据库相关技术内容!
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • liyue071714118
    栈主

小栈成员

查看更多
  • liu_di888
  • gaokeke123
  • Jack2k
  • miemieMIA
戳我,来吐槽~