如何在同一个 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
操作,它将添加在SELECT
和ORDER BY
之间:
FROM MonitoringJob
SELECT Category, CreationDate
DISTINCT
ORDER BY CreationDate DESC
SELECT Category
但是现在,有了扩展的排序键列 CreationDate
,DISTINCT
操作的语义已经改变,因此结果将不再相同。这不是我们想要的,因此 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 个结果(有大量重复的 length
s)而它下面的查询只给出了 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?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Redshift 中的 select 语句中使用存储过程