SQL Server - 尝试计算SELECT DISTINCT查询

时间:2017-10-23 19:43:38

标签: sql sql-server distinct greatest-n-per-group sql-server-2016

我有一个简单的三栏表,显示我们的系统上次检查某个网址的日期,以及与该网站相关联的ID编号。

如果我要运行以下查询:

SELECT
SourceId,
Url,
Date
FROM Table1

我最终得到以下结果:

SourceId   Url                  Date
1          www.google.com/abc   2017-10-21
1          www.google.com/def   2017-10-22
1          www.google.com/ghi   2017-10-18
2          www.yahoo.com/123    2017-09-20
2          www.yahoo.com/456    2017-09-27
2          www.yahoo.com/789    2017-10-01
3          www.youtube.com/xyz  2017-07-08
3          www.youtube.com/prs  2017-08-01
3          www.youtube.com/mno  2017-07-16

我需要的是每个源ID只有一个记录,并且它是与该源ID相关联的最新日期;最后,我希望整个列表按源ID按升序排序。因此结果如下:

SourceId   Url                  Date
1          www.google.com/def   2017-10-22
2          www.yahoo.com/789    2017-10-01
3          www.youtube.com/prs  2017-08-01

我知道我必须以ORDER BY SourceId结束查询。这是我最近遇到麻烦的每个来源的一个记录。我以为我应该在SourceId上使用DISTINCT,但它似乎不起作用,因为它在其他列中寻找重复的值?

编辑 - 更新了网址列中包含错误值的结果。

5 个答案:

答案 0 :(得分:3)

您可以使用row_number窗口函数每个ID仅查询一行:

SELECT   [SourceId], [Url], [Date]
FROM     (SELECT [SourceId], [Url], [Date],
                 ROW_NUMBER() OVER (PARTITION BY [SourceId]
                                    ORDER BY [Date] DESC) AS rn
          FROM   Table1) t
WHERE    rn = 1
ORDER BY [SourceId] ASC

答案 1 :(得分:2)

使用NOT EXISTS

 SELECT
   SourceId,
   Url,
   Date
 FROM Table1 t1
 WHERE NOT EXISTS (
   SELECT 1
   FROM table1 t2
   WHERE t1.SourceId = t2.SourceId and t2.date > t1.date
 )
 ORDER BY SourceId 

答案 2 :(得分:2)

您可以将WITH TIES子句与Row_Number()

一起使用

示例

Select top 1 with ties *
 From  YourTable
 Order By Row_Number() over (Partition By SourceID Order By Date Desc)

<强>返回

SourceId    Url                 Date
1           www.google.com/def  2017-10-22
2           www.yahoo.com/789   2017-10-01
3           www.youtube.com/prs 2017-08-01
  

编辑测试

/*
Drop Table #Temp
Select N
      ,S = newid()
 Into  #Temp
 From (Select Top 1000000 N=Row_Number() Over (Order By (Select NULL)) From master..spt_values n1, master..spt_values n2) A
*/

 Select Top 1 with ties * 
  from  #Temp
  Order By Row_Number() over (Partition By left(S,2) Order by N Desc)

Select *
 From (
        Select *,RN=Row_Number() over (Partition By left(S,2) Order by N Desc)
         From  #Temp
      ) A
 Where RN=1

结果

Run With Ties   RN
1   1.83        5.444
2   1.9         5.444
3   1.913       6.374
4   1.957       5.8
5   1.833       6.244

Avg 1.8866      5.8612

enter image description here

答案 3 :(得分:1)

T-SQL: -

  SELECT * FROM  
( SELECT *,ROW_NUMBER() OVER (PARTITION BY [SOURCEID] ORDER BY [Date] desc) AS ROW_NUMBER FROM [TABLE1] ) AS ROWS
  WHERE ROW_NUMBER = 1 

输出: -

enter image description here

答案 4 :(得分:1)

Mureinik的回答显示了我会这样做的方式,而且我也赞成了John Cappelletti的回答,因为我认为它显示了一个有趣的替代结构,即使它的评论引起了一些性能问题。

我只想添加一些东西。首先,您对DISTINCT无法正常工作的假设是正确的:如果您在其中编写SELECT语句,其中DISTINCT适用于所有选择列表中的字段,而不仅仅是一个。如果您需要一组不同的值 plus 一些关于它们的其他信息,那么像DISTINCT这样的窗口函数应该是您首先想到的。

其次,虽然row_number()偶尔有用,但我认为这是一个被滥用的功能。当我正在阅读或修改现有查询并看到DISTINCT时,我立刻想知道查询的原始作者是否真的需要它,或者他/她是否用它来掩盖其他地方的一些可疑逻辑查询,例如使用内部或外部联接,其中semi-join更合适。大多数情况下,后者最终成为现实。当您考虑撰写DISTINCT时,使用此问题的其他答案中显示的功能,停止并问自己是否可能存在更好的解决方案是值得的。