如何在同一个SELECT语句中使用DISTINCT和ORDER BY?


116

执行以下语句后:

SELECT  Category  FROM MonitoringJob ORDER BY CreationDate DESC

我从数据库中获取以下值:

test3
test3
bildung
test4
test3
test2
test1

但我想删除重复项,如下所示:

bildung
test4
test3
test2
test1

我尝试使用DISTINCT,但是在一个语句中它不适用于ORDER BY。请帮忙。

重要:

  1. 我尝试过:

    SELECT DISTINCT Category FROM MonitoringJob ORDER BY CreationDate DESC

    它不起作用。

  2. 通过CreationDate进行排序非常重要。


1
它怎么不起作用?输出错误?
Fedearne 2011年

Answers:


194

问题在于,ORDER BY中未指定在中使用的列DISTINCT。为此,您需要使用聚合函数进行排序,然后使用a GROUP BY进行DISTINCT工作。

尝试这样的事情:

SELECT DISTINCT Category, MAX(CreationDate) 
FROM MonitoringJob 
GROUP BY Category 
ORDER BY MAX(CreationDate) DESC, Category

98
如果您按类别分组,则甚至不需要DISTINCT关键字。
MatBailie 2011年

18

扩展排序键列

您想要执行的操作不起作用的原因是由于SQL中的逻辑操作顺序,对于您的第一个查询,该操作的顺序是(简化的):

  • FROM MonitoringJob
  • SELECT Category, CreationDate即添加一个所谓的扩展排序键列
  • ORDER BY CreationDate DESC
  • SELECT Category即再次从结果中删除扩展的排序键列

因此,由于采用了SQL标准扩展的排序键列功能,因此完全有可能按SELECT子句中未包含的内容进行排序,因为它是在后台临时添加的。

那么,为什么不起作用DISTINCT呢?

如果我们添加DISTINCT操作,则会在SELECT和之间添加ORDER BY

  • FROM MonitoringJob
  • SELECT Category, CreationDate
  • DISTINCT
  • ORDER BY CreationDate DESC
  • SELECT Category

但是现在,随着 扩展的排序键列 CreationDateDISTINCT操作的语义已更改,因此结果将不再相同。这不是我们想要的,因此SQL标准和所有合理的数据库都禁止这种用法。

解决方法

可以使用以下标准语法进行仿真

SELECT Category
FROM (
  SELECT Category, MAX(CreationDate) AS CreationDate
  FROM MonitoringJob
  GROUP BY Category
) t
ORDER BY CreationDate DESC

或者,只是简单地(在这种情况下),如Prutswonder所示

SELECT Category, MAX(CreationDate) AS CreationDate
FROM MonitoringJob
GROUP BY Category
ORDER BY CreationDate DESC

我在这里已详细介绍了SQL DISTINCT和ORDER BY


1
我认为您对DISTINCT ON工作方式有误,并且可以肯定这对您没有帮助。括号中的表达式是用来确定不同性(分组条件)的。如果存在相同的不同类别,CreationDate那么结果中只会显示其中一个!因为我想知道是否可能是某种错误,所以我还将示例数据库加载到您的博客文章中以进行仔细检查:DISTINCT ON您在此处给出的查询总共产生了1000个结果(带有大量重复的lengths),而其下的查询给出了仅140(唯一)值。
Inkling

@Inkling:谢谢您的时间。OP明确希望删除“重复项”。参见OP的措辞“但我希望这样删除重复项”。从我的博客文章中复制查询时,您可能犯了一个错误。有两个查询,一个使用DISTINCT(no ON),一个使用DISTINCT ON。请注意,后者显然不会删除重复的长度,但会删除重复的标题。我确实认为我的回答完全正确。
卢卡斯·埃德

1
我的观点是,您的DISTINCT ON条件正在使用错误的条件删除重复项。在您的博客文章中,DISTINCT ON查询确实删除了重复的标题,但是DISTINCT上面的查询和下面的查询(您声称它是“语法糖”)都删除了重复的长度,因为这可能是整个目标。同样的情况适用于此:OP希望删除重复的Categories,而不是像查询一样重复CreationDatesDISTINCT ON。如果您仍然不相信我,请对自己进行测试。
Inkling

6

如果不需要MAX(Cre​​ationDate)的输出-就像原始问题的示例一样-唯一的答案是Prashant Gupta答案的第二条语句:

SELECT [Category] FROM [MonitoringJob] 
GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

说明:不能在内联函数中使用ORDER BY子句,因此Prutswonder答案中的语句在这种情况下不可用,您不能在其周围放置外部选择并丢弃MAX(Cre​​ationDate)部分。


2

只需使用此代码,如果您想要[Category]和[CreationDate]列的值

SELECT [Category], MAX([CreationDate]) FROM [MonitoringJob] 
             GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

或使用此代码,如果只需要[Category]列的值。

SELECT [Category] FROM [MonitoringJob] 
GROUP BY [Category] ORDER BY MAX([CreationDate]) DESC

您将拥有所有想要的独特记录。


这些花括号[]完全令人困惑...这是有效的SQL语法吗?
m13r 2014年

1
方括号用于转义关键字,例如Order,event等,因此,如果(例如)表中有一个称为的列,则Event可以编写[Event]而不是Event停止SQL引发解析错误。
本·麦克斯菲尔德

1

2)通过CreationDate排序非常重要

原始结果表明“ test3”有多个结果...

始终开始使用MAX来删除Group By中的重复项是非常容易的……而忘记或忽略了潜在的问题是什么……

OP大概意识到使用MAX会给他最后一个“创建”,而使用MIN会给他第一个“创建” ...


3
这似乎并没有真正回答问题,这似乎是对其他回答者对的使用的评论MAX,而不是独立地作为对问题的回答。
DaveyDaveDave

0
if object_id ('tempdb..#tempreport') is not null
begin  
drop table #tempreport
end 
create table #tempreport (
Category  nvarchar(510),
CreationDate smallint )
insert into #tempreport 
select distinct Category from MonitoringJob (nolock) 
select * from #tempreport  ORDER BY CreationDate DESC

0

通过子查询,它应该工作:

    SELECT distinct(Category) from MonitoringJob  where Category in(select Category from MonitoringJob order by CreationDate desc);

嗯...我认为不会。外部选择未排序。
Hossam El-Deen

它不会工作,我在这里是因为这不工作
Amirreza

-1

Distinct将按升序对记录进行排序。如果要按降序排序,请使用:

SELECT DISTINCT Category
FROM MonitoringJob
ORDER BY Category DESC

如果要基于CreationDate字段对记录进行排序,则此字段必须在select语句中:

SELECT DISTINCT Category, creationDate
FROM MonitoringJob
ORDER BY CreationDate DESC

12
这将执行,但不会给出OP所需的内容。OP需要不同的类别,而不是Category和CreateDate的不同组合。此代码可以产生相同类别的多个实例,每个实例具有不同的CreationDate值。
MatBailie 2011年

-1

您可以使用CTE:

WITH DistinctMonitoringJob AS (
    SELECT DISTINCT Category Distinct_Category FROM MonitoringJob 
)

SELECT Distinct_Category 
FROM DistinctMonitoringJob 
ORDER BY Distinct_Category DESC

-3

请尝试下一个,但是对于海量数据并没有用...

SELECT DISTINCT Cat FROM (
  SELECT Category as Cat FROM MonitoringJob ORDER BY CreationDate DESC
);

4
“除非另外指定了TOP或FOR XML,否则ORDER BY子句在视图,内联函数,派生表,子查询和公用表表达式中无效。”
TechplexEngineer

这不起作用,因为您未在订单依据上指定列CreationDate。
Mauro Bilotti 2014年

1
@TechplexEngineer您的评论不正确。使用ORDER BY子查询是绝对有效的。甚至有人投票赞成您的错误评论。
Racil Hilan 2014年

我正在尝试此问题,并且与@TechplexEngineer遇到相同的错误。我使用自定义排序的情况下。
Ege Bayrak

-4

可以使用内部查询来完成

$query = "SELECT * 
            FROM (SELECT Category  
                FROM currency_rates                 
                ORDER BY id DESC) as rows               
            GROUP BY currency";

-5
SELECT DISTINCT Category FROM MonitoringJob ORDER BY Category ASC

2
我需要按创建日期排序!非常重要
rr

因此,不可能自己添加要订购的列吗?您的示例显示了按字母顺序排列的条目。如果您需要按创建日期排序,只需添加它即可。确实没有那么困难。
Furicane 2011年

8
-1:OP尝试这样做,但是没有用,因为这是不可能的,并且您在光顾OP时显然忽略了这一事实。关键是DISTINCT运算符将整理具有相同“类别”值的几条记录,每条记录的创建日期可能不同。因此,使用DISTINCT在逻辑上是不可能的。这会将所需的逻辑推到GROUP BY而不是DISTINCT,从而允许在创建日期进行汇总(MAX)。
MatBailie 2011年

实际上,如果您仔细研究一下OP所做的事情,那绝对是格式错误的SQL-我没有犯一个错误,给出的结果与他所要求的相对应。我不会为-1烦恼,只是在下次纠正人之前阅读。谢谢。
Furicane 2011年

8
您直接建议添加CreationDate字段,甚至说“这并不难”。这样做会产生格式错误的SQL。您因光顾OP而得到-1,给出了使OP返回到他最初发布的语句的建议,并且没有注意到DISTINCT与非DISTINCT字段之间的排序之间的争用。另外,“ b”在“ t”之前,“ 1”在“ 4”之前,因此OP给出的结果绝对不是按字母顺序排列的。那么,我可以提出您自己的建议吗:下次请仔细阅读。
MatBailie 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.