在数据库查询中,DISTINCT、TOP和ORDER BY是三个常用的关键字,它们各自有着独特的功能,但当它们组合在一起使用时,会产生什么样的效果呢?本文将通过SQLServer Management Studio和AdventureWorks2012数据库的实例,来探讨这些关键字是如何协同工作的。
首先,来探讨DISTINCT和TOP关键字的执行顺序。例如,以下SQL查询:
SELECT DISTINCT TOP 10 FirstName, LastName FROM Person.Person ORDER BY LastName;
这个查询的目的是返回一个包含独特第一和最后名字的列表。TOP 10将从排序后的集合中返回前十个项目,而DISTINCT将移除任何重复项。问题是,哪个操作先执行?是先根据LastName排序,然后取前十个项目,再移除重复的名字?还是先移除重复项,然后对项目进行排序,并显示前十个项目?
在回答这个问题之前,需要记住的是DISTINCT作用于SELECT子句中的所有列和表达式。因此,在这种情况下,该语句将返回FirstName和LastName的不重复行。
遗憾的是,没有直接的方法可以在一个字段集上使用DISTINCT,而在显示结果中使用其他字段。一旦向SELECT语句添加了列,它们就受到DISTINCT操作符的影响。虽然可以通过一个INNER JOIN来获取一个不重复的列表,然后使用其他列,但这样做可能会有风险,因为JOIN可能会重新引入重复项。
要确定DISTINCT和TOP哪个先执行,可以观察以下两个查询的结果:
SELECT DISTINCT FirstName, LastName FROM Person.Person ORDER BY LastName;
和
SELECT DISTINCT TOP 10 FirstName, LastName FROM Person.Person ORDER BY LastName;
比较这两个查询的结果,可以看到“DISTINCT TOP 10”查询包含了“DISTINCT”查询的前10行。这说明首先创建了一个DISTINCT列表,然后返回了TOP 10项。
可以通过显示查询计划来确认这一点。在执行查询之前,选择“查询”->“包含实际查询计划”。在查询计划中,“Stream Aggregate”图标代表DISTINCT操作,“Top”代表TOP 10操作。
接下来,探讨Nan的问题的第二部分,即DISTINCT操作符如何处理表达式。表达式与列在DISTINCT和TOP方面是相同的。让从一个SELECT语句开始,获取名字以及全名,全名是通过将LastName附加到FirstName上来创建的。
SELECT DISTINCT FirstName, FirstName + ' ' + LastName AS FullName FROM Person.Person ORDER BY LastName;
请注意,当使用ORDER BY时,ORDER BY的项必须出现在SELECT列表中,当使用Distinct时。因此,必须修改原始问题中提出的语句:
这个语句:
SELECT FirstName, FirstName + ' ' + LastName AS FullName FROM Person.Person ORDER BY FirstName + ' ' + LastName;
会返回19972行。当添加DISTINCT:
SELECT DISTINCT FirstName, FirstName + ' ' + LastName AS FullName FROM Person.Person ORDER BY FirstName + ' ' + LastName;
然后返回19516行。最后添加TOP 10,返回前10个不同的名称组合。
SELECT DISTINCT TOP 10 FirstName, FirstName + ' ' + LastName AS FullName FROM Person.Person ORDER BY FirstName + ' ' + LastName;
尝试在AdventureWorks数据库上运行这些查询,将看到行为与仅使用列时发现的行为相同。