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

Posted

技术标签:

【中文标题】如何在同一个 SELECT 语句中使用 DISTINCT 和 ORDER BY?【英文标题】:How to use DISTINCT and ORDER BY in same SELECT statement? 【发布时间】:2011-07-20 11:29:44 【问题描述】:

执行以下语句后:

SELECT  Category  FROM MonitoringJob ORDER BY CreationDate DESC

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

test3
test3
bildung
test4
test3
test2
test1

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

bildung
test4
test3
test2
test1

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

重要:

    我试过了:

    SELECT DISTINCT Category FROM MonitoringJob ORDER BY CreationDate DESC
    

    它不起作用。

    CreationDate 的顺序非常重要。

【问题讨论】:

怎么不行?输出错误? 如果你使用postgres,显然你可以SELECT DISTINCT ON (value), * FROM table ORDER BY value, and_the_value_you_want_to_order_from DESC 【参考方案1】:

问题在于ORDER BY 中使用的列未在DISTINCT 中指定。为此,您需要使用aggregate function 进行排序,并使用GROUP BY 使DISTINCT 工作。

试试这样的:

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

【讨论】:

如果您按类别分组,您甚至不需要 DISTINCT 关键字。 为了解释为什么你需要一个聚合函数(在你的 ORDER BY 中,不一定在你的 SELECT 中!),我找到了一篇简洁的文章:weblogs.sqlteam.com/jeffs/2007/12/13/… TLDR: When using MIN() or MAX() 对 GROUP BY 之后的每一行,它抓取组中的最大值或最小值。【参考方案2】:

扩展的排序键列

您想要做的事情不起作用的原因是因为logical order of operations in SQL,对于您的第一个查询,它是(简化的):

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

因此,由于 SQL 标准的扩展排序键列 功能,完全可以按不在 SELECT 子句中的内容进行排序,因为它是在后面临时添加的场景。

那么,为什么这不适用于DISTINCT

如果我们添加DISTINCT 操作,它将添加在SELECTORDER 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

I have blogged about SQL DISTINCT and ORDER BY more in detail here.

【讨论】:

我认为您误解了DISTINCT ON 的工作原理,并且很确定它在这里没有帮助。括号中的表达式用于确定区别(分组条件)。如果有不同的类别具有相同的CreationDate,那么结果中只会出现其中一个!因为我想知道我是不是错了,所以我还在您的博客文章中加载了示例数据库以进行仔细检查:您在那里提供的 DISTINCT ON 查询总共产生了 1000 个结果(有大量重复的 lengths)而它下面的查询只给出了 140 个(唯一)值。 @Inkling:感谢您的宝贵时间。 OP 明确希望删除“重复项”。请参阅 OP 的措辞 “但我希望删除重复项,就像这样”。从我的博客文章中复制查询时,您可能犯了一个错误。有两种查询,一种使用DISTINCT(没有ON),另一种使用DISTINCT ON。请注意,后者明确不会删除重复的长度,而是删除重复的标题。我确实认为我在这里的回答是完全正确的。 我的意思是您的DISTINCT ON 条件正在使用错误的条件删除重复项。在您的博客文章中,DISTINCT ON 查询确实删除了重复的 titles,但是它上面的 DISTINCT 查询和它下面的查询(您声称它是“语法糖”)都删除了重复的长度,因为这大概是整个目标。这里同样适用:OP 希望删除重复的 Categories,而不是像 DISTINCT ON 查询那样重复的 CreationDates。如果你仍然不相信我,你自己测试一下。【参考方案3】:

如果不需要 MAX(CreationDate) 的输出 - 就像在原始问题的示例中一样 - 唯一的答案是 Prashant Gupta 答案的第二个陈述:

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

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

【讨论】:

【参考方案4】:

只需使用此代码,如果您想要 [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 语法吗? 括号用于转义关键字,例如订单、事件等,因此如果您的表中有(例如)名为Event 的列,您可以写[Event] 而不是@987654325 @ 停止 SQL 引发解析错误。【参考方案5】:

2) 按 CreationDate 排序很重要

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

很容易开始一直使用 MAX 来删除 Group By 中的重复项……忘记或忽略根本问题是什么……

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

【讨论】:

这似乎并没有真正回答这个问题,它似乎是对其他回答者使用MAX 的评论,而不是作为对问题的独立答案的评论。跨度> 【参考方案6】:
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

【讨论】:

【参考方案7】:

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

SELECT DISTINCT Category
FROM MonitoringJob
ORDER BY Category DESC

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

SELECT DISTINCT Category, creationDate
FROM MonitoringJob
ORDER BY CreationDate DESC

【讨论】:

这将执行但不会提供 OP 所需的内容。 OP 想要不同的类别,而不是类别和 CreateDate 的不同组合。此代码可以生成同一类别的多个实例,每个实例具有不同的 CreationDate 值。【参考方案8】:

您可以使用 CTE:

WITH DistinctMonitoringJob AS (
    SELECT DISTINCT Category Distinct_Category FROM MonitoringJob 
)

SELECT Distinct_Category 
FROM DistinctMonitoringJob 
ORDER BY Distinct_Category DESC

【讨论】:

【参考方案9】:

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

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

【讨论】:

嗯...我认为不会。外部选择未排序。 这行不通,我在这里是因为这行不通 一点帮助都没有!【参考方案10】:

下一个试试,但是对大数据没用...

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

【讨论】:

"ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效,除非还指定了 TOP 或 FOR XML。" 这不起作用,因为您没有在 order by 上指定列 CreationDate。 @TechplexEngineer 您的评论不正确。在子查询中使用ORDER BY 是绝对有效的。甚至有人对你的错误评论投了赞成票。 我正在尝试这个并且与@TechplexEngineer 有同样的错误。我正在使用带有 case when 的自定义排序。【参考方案11】:

可以像这样使用内部查询来完成

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

【讨论】:

【参考方案12】:
SELECT DISTINCT Category FROM MonitoringJob ORDER BY Category ASC

【讨论】:

我需要按创建日期排序!!这很重要 那么是不是不能自己添加要订购的栏目呢?您的示例显示按字母顺序排列的条目。如果您需要按创建日期排序,只需添加它。真的没那么难。 -1 :OP 尝试过,但没有成功,因为这是不可能的,而且您在光顾 OP 时显然忽略了这一事实。关键是 DISTINCT 运算符将整理多个具有相同类别值的记录,每个记录可能具有不同的创建日期。因此,使用 DISTINCT 在逻辑上是不可能的。这会将所需的逻辑推送到 GROUP BY 而不是 DISTINCT,从而允许在创建日期进行聚合 (MAX)。 实际上,如果您仔细看看 OP 做了什么,那绝对是格式错误的 SQL - 我没有犯任何错误,并且给出的结果与他要求的结果相对应。我不会费心-1,下次纠正人之前阅读。谢谢。 你直接建议添加CreationDate字段,甚至说“真的没那么难”。这样做会产生格式错误的 SQL。您因光顾 OP、提供建议以使 OP 回到他最初发布的声明,并且没有注意到 DISTINCT 和按不在 DISTINCT 中的字段排序之间的争用而得到 -1。此外,“b”在“t”之前,“1”在“4”之前,因此 OP 给出的结果绝对不是按字母顺序排列的。那么我可以提出你自己的建议吗:下次阅读(更仔细地)。

以上是关于如何在同一个 SELECT 语句中使用 DISTINCT 和 ORDER BY?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 select 语句中使用索引?

如何在 Redshift 中的 select 语句中使用存储过程

如何在单个 SELECT 语句中拥有多个公用表表达式?

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

mysql 求和语句

如何在函数的 UPDATE 或 SELECT 语句中使用动态列名?