【问题标题】:Eliminating duplicate values based on only one column of the table仅基于表的一列消除重复值
【发布时间】:2013-07-04 16:17:12
【问题描述】:

我的查询:

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

输出的第一部分:

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

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

【问题讨论】:

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


    【解决方案1】:

    我使用这种模式解决了这样的查询:

    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表的索引范围扫描只扫描第一项就可以了。

    【讨论】:

      【解决方案2】:

      从您的示例中,假设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;
      

      【讨论】:

        【解决方案3】:

        这就是窗口函数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
        

        【讨论】:

        • 你能解释一下这个查询吗?
        • @JacksOnF1re 。 . .你知道row_number() 做什么吗?它枚举组中的行(由partition by 子句定义)。排序基于order by 子句。通过选择值 1,每组只选择一行,这将是日期最大的一行。
        • 哇,Gordon 花了 2 分钟才想到这个。嗯。
        • steve-o 你的意思是他马上就看到了帖子哈哈。它可能花了一分钟或更短的时间。超级令人印象深刻
        猜你喜欢
        • 2018-05-01
        • 2021-01-31
        • 1970-01-01
        • 2021-06-04
        • 2016-04-26
        • 1970-01-01
        • 2017-12-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多