仅基于表的一列消除重复值

时间:2013-07-06 23:07:20

标签: sql sql-server distinct inner-join duplicate-removal

我的查询:

SELECT sites.siteName, sites.siteIP, history.date
FROM sites INNER JOIN
     history ON sites.siteName = history.siteName
ORDER BY siteName,date

输出的第一部分:

enter image description here

如何删除siteName列中的重复项?我想只保留基于date列的更新版本。

在上面的示例输出中,我需要行1,3,6,10

3 个答案:

答案 0 :(得分:26)

这是窗口函数row_number()派上用场的地方:

SELECT s.siteName, s.siteIP, h.date
FROM sites s INNER JOIN
     (select h.*, row_number() over (partition by siteName order by date desc) as seqnum
      from history h
     ) h
    ON s.siteName = h.siteName and seqnum = 1
ORDER BY s.siteName, h.date

答案 1 :(得分:8)

从您的示例中可以合理地假设siteIP列由siteName列确定(即每个网站只有一个siteIP)。如果确实如此,那么使用group by

就有一个简单的解决方案
select
  sites.siteName,
  sites.siteIP,
  max(history.date)
from sites
inner join history on
  sites.siteName=history.siteName
group by
  sites.siteName,
  sites.siteIP
order by
  sites.siteName;

但是,如果我的假设不正确(也就是说,某个网站可能有多个siteIP),那么您不清楚哪个siteIP您希望查询到哪个siteIP返回第二列。如果只有select sites.siteName, min(sites.siteIP), max(history.date) from sites inner join history on sites.siteName=history.siteName group by sites.siteName order by sites.siteName; ,则以下查询将执行:

{{1}}

答案 2 :(得分:0)

我使用这种模式解决此类查询:

SELECT *
FROM t
WHERE t.field=(
  SELECT MAX(t.field) 
  FROM t AS t0 
  WHERE t.group_column1=t0.group_column1
    AND t.group_column2=t0.group_column2 ...)

也就是说,它将选择字段值处于最大值的记录。要将其应用于您的查询,我使用了公用表表达式,因此不必重复两次JOIN:

WITH site_history AS (
  SELECT sites.siteName, sites.siteIP, history.date
  FROM sites
  JOIN history USING (siteName)
)
SELECT *
FROM site_history h
WHERE date=(
  SELECT MAX(date) 
  FROM site_history h0 
  WHERE h.siteName=h0.siteName)
ORDER BY siteName

重要的是要注意,它仅在我们要计算最大值的字段是唯一的时才有效。在您的示例中,date字段对于每个siteName应该是唯一的,也就是说,如果IP不能每毫秒多次更改。以我的经验,通常是这种情况,否则无论如何您都不知道哪个记录是最新的。如果history表具有(site, date)的唯一索引,则此查询也非常快,可以使用history表上的索引范围扫描仅扫描第一项。