这两个查询是否相同 - GROUP BY与DISTINCT?

时间:2010-07-28 15:11:48

标签: sql sql-server sql-server-2008 group-by

这两个查询似乎返回相同的结果。这是巧合还是真的一样?

1

SELECT t.ItemNumber,
  (SELECT TOP 1 ItemDescription
   FROM Transactions
   WHERE ItemNumber = t.ItemNumber
   ORDER BY DateCreated DESC) AS ItemDescription
FROM Transactions t
GROUP BY t.ItemNumber

2

SELECT DISTINCT(t.ItemNumber),
  (SELECT TOP 1 ItemDescription
   FROM Transactions
   WHERE ItemNumber = t.ItemNumber
   ORDER BY DateCreated DESC) AS ItemDescription
FROM Transactions t

一点解释: 我正试图从一个充满交易的表中获得一个独特的项目列表。对于每个项目,我正在寻找ItemNumber(标识字段)和最新的ItemDescription。

8 个答案:

答案 0 :(得分:5)

你的例子#2让我挠了一会儿 - 我心里想:“你不能DISTINCT一栏,这意味着什么?” - 直到我意识到发生了什么。

当你有

SELECT DISTINCT(t.ItemNumber)

,尽管出现了,但实际上要求t.ItemNumber 的不同值!您的示例#2实际上被解析为与

相同
SELECT DISTINCT
  (t.ItemNumber)
  ,
  (SELECT TOP 1 ItemDescription
   FROM Transactions
   WHERE ItemNumber = t.ItemNumber
   ORDER BY DateCreated DESC) AS ItemDescription
FROM Transactions t

t.ItemNumber周围使用语法正确但多余的括号。 <{1}}适用于整个结果集。

在这种情况下,由于您的DISTINCT组按实际不同的列进行,因此您会得到相同的结果。我实际上有点惊讶的是SQL Server没有(在GROUP BY示例中)坚持在GROUP BY列表中提到了subqueried列。

答案 1 :(得分:4)

相同的结果,但第二个似乎有一个更昂贵的排序步骤,以在我的快速测试中应用DISTINCT

ROW_NUMBER虽然......

,但两人都被看不见了
with T as
(
SELECT ItemNumber, 
       ItemDescription,
       ROW_NUMBER() OVER ( PARTITION BY ItemNumber ORDER BY DateCreated DESC) AS RN
FROM Transactions
)
SELECT * FROM T
WHERE RN=1

修改 ...而我的测试设置又被Joe's solution重击。

Plans http://img842.imageshack.us/img842/4105/executionplan.png

测试设置

CREATE TABLE Transactions
(
ItemNumber INT not null,
ItemDescription VARCHAR(50) not null,
DateCreated DATETIME not null
)

INSERT INTO Transactions
SELECT 
number, NEWID(),DATEADD(day, cast(rand(CAST(newid() as varbinary))*10000 
  as int),getdate()) 
FROM master.dbo.spt_values

ALTER TABLE dbo.Transactions ADD CONSTRAINT
    PK_Transactions PRIMARY KEY CLUSTERED 
    (ItemNumber,DateCreated) 

答案 2 :(得分:3)

如果你至少跑了2005并且可以使用CTE,那么恕我直言就更清洁。

编辑:正如Martin's answer所指出的,这也表现得更好。

;with cteMaxDate as (
    select t.ItemNumber, max(DateCreated) as MaxDate
        from Transactions t
        group by t.ItemNumber
)
SELECT t.ItemNumber, t.ItemDescription
    FROM cteMaxDate md
        inner join Transactions t
            on md.ItemNumber = t.ItemNumber
                and md.MaxDate = t.DateCreated

答案 3 :(得分:3)

基于数据&amp;简单的查询,都会返回相同的结果。但是,基本操作是非常不同的。

DISTINCT,正如AakashM击败我指出的那样,应用于 所有 列值,包括来自子选择和计算列的值。 所有DISTINCT所做的就是根据所涉及的所有列,从可见性 中删除重复项。这就是为什么它通常被认为是黑客攻击的原因,因为人们会使用它来摆脱重复,而不理解为什么查询首先返回它们(因为它们应该使用INEXISTS而不是通常是一个连接。 PostgreSQL是我所知道的唯一一个带有DISTINCT ON子句的数据库,它可以像OP那样工作。

GROUP BY子句不同 - 它主要用于分组以准确使用聚合函数。要为该功能提供服务,列值将是基于GROUP BY子句中定义的值的唯一值。此查询永远不需要DISTINCT,因为感兴趣的值已经是唯一的。

结论

这是一个糟糕的例子,因为它将DISTINCT和GROUP BY描述为等于它们不等。

答案 4 :(得分:2)

是的,他们会返回相同的结果。

答案 5 :(得分:2)

由于您没有使用任何聚合函数,因此SQL Server应该足够聪明,可以将GROUP BY视为DISTINCT

您可能还有兴趣查看以下Stack Overflow帖子,以便进一步阅读此主题:

答案 6 :(得分:1)

在SQL查询中使用聚合函数时,需要

GROUP BY才能正确返回结果。由于您没有使用聚合函数,因此不需要GROUP BY,因此查询是相同的。

答案 7 :(得分:1)

是的,他们会返回相同的结果。

通常,group by子句(找到here)按照提到的特定列对行进行分组,如果你在select语句中有一个总和。因此,如果你有一个像这样的表:

O_Id        OrderDate   OrderPrice      Customer
1           2008/11/12  1000            Hansen
2           2008/10/23  1600            Nilsen
3           2008/09/02  700             Hansen
4           2008/09/03  300             Hansen
5           2008/08/30  2000            Jensen
6           2008/10/04  100             Nilsen

如果您按客户分组并要求获得金额或订单价格

Customer    SUM(OrderPrice)
Hansen          2000
Nilsen             1700
Jensen          2000

与此相反,distinct(找到here)只是使它没有重复的行。在这种情况下,原始表将保持不变,因为每一行都与其他行不同。