【问题标题】:Remove dupes from recordset excluding columns from dupe condition从记录集中删除重复,不包括重复条件中的列
【发布时间】:2009-12-04 19:28:28
【问题描述】:

我遇到了一个 mssql 数据库,有一个类似...的 SQL 查询

SELECT id, type, start, stop, one, two, three, four
FROM a
UNION ALL
SELECT id, type, start, stop, one, two, three, four
FROM b
UNION ALL
SELECT id, type, start, stop, one, two, three, four
FROM c
ORDER BY type ASC

导致...

row |  id  type  start       stop         one   two    three   four
----+--------------------------------------------------------------
 1  |  1   a     2010-01-01  2010-01-31   100   1000   1000    100
 2  |  1   a     2010-02-01  2010-12-31   100   500    500     50
 3  |  1   b     2010-01-01  2010-01-31   100   NULL   NULL    100
 4  |  1   b     2010-01-01  2010-12-31   100   NULL   NULL    100
 5  |  1   c     2010-01-01  2010-01-31   0     NULL   NULL    100
 6  |  1   c     2010-01-01  2010-12-31   0     NULL   NULL    100

不过,我更喜欢下面的结果……

row |  id  type  start       stop         one   two    three   four
----+--------------------------------------------------------------
 1  |  1   a     2010-01-01  2010-01-31   100   1000   1000    100
 2  |  1   a     2010-02-01  2010-12-31   100   500    500     50
 4  |  1   b     2010-01-01  2010-12-31   100   NULL   NULL    100
 6  |  1   c     2010-01-01  2010-12-31   0     NULL   NULL    100

也就是说,删除第 3 行和第 5 行,因为它们在各方面都与第 4 行和第 6 行相同 停止-列,而不幸的行有排除stop-列中的最低值。

我怎样才能做到这一点? 我一直在想……

SELECT * FROM (
    SELECT id, type, start, stop, one, two, three, four
    FROM a
    UNION ALL
    SELECT id, type, start, stop, one, two, three, four
    FROM b
    UNION ALL
    SELECT id, type, start, stop, one, two, three, four
    FROM c
    ORDER BY type ASC
) AS types
GROUP BY ... HAVING ???

我需要指导,请帮忙。

(不,我无法改变任何条件,我必须处理给定的情况。)

【问题讨论】:

    标签: sql group-by distinct


    【解决方案1】:

    已提出并回答了类似的问题。例如:Select uniques, and one of the doubles

    而且你的情况更简单(如果我理解你的问题描述正确的话):

    select id, type, start, max(stop), one, two, three, four
        from (...) types
        group by id, type, start, one, two, three, four
        order by ...
    

    代替(...),您可以从a、b 和c 中选择。 只需省略 order by 子句。

    或者,如果不是 (id, type, start)->(one, 二, 三, 四) 你有 (id, type, start, stop)->(一, 二, 三, 四) (意思您必须选择其他对应的列 到 max(stop)),这个查询通常会产生合理的执行计划:

    select id, type, start, stop, one, two, three, four
        from (...) types
        where stop = (select max(stop)
                      from (...) t2
                      where t2.id = types.id
                            and t2.type = types.type
                            and t2.start = types.start)
    

    但这取决于数据在源表之间的分布方式以及存在的索引。在某些情况下,上面链接中的解决方案可能仍然更好。

    【讨论】:

      【解决方案2】:

      这应该可行:

      SELECT
           id,
           type,
           start,
           stop,
           one,
           two,
           three,
           four
      FROM
           A T1
      LEFT OUTER JOIN A T2 ON
           T2.id = T1.id AND
           T2.type = T1.type AND
           T2.start = T1.start AND
           T2.one = T1.one AND
           ...
           T2.stop > T1.stop
      WHERE
           T2.id IS NULL     -- This must be a NOT NULL column for this to work
      

      这假定 type 列的值与示例中的表名相同。如果您可能在表之间有重复的行,那么您需要使用您所拥有的而不是 A 的子查询来执行相同的逻辑。如果我的假设是正确的,那么只需将您的三个 UNION ALL 查询中的每一个替换为上面的,改变表名。

      这个想法是,如果存在匹配的行,但停止日期较晚,那么您不希望在结果中包含该行。使用 LEFT OUTER JOIN,T2.id 为 NULL 的唯一方法是如果没有这样的匹配,所以我们可以将它包含在结果集中(这就是为什么 id 必须是一个 NOT NULL 列才能工作。)

      既然你说你不能改变数据库,我就饶了你,“这个设计很糟糕”的谴责;)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-06
        • 2015-11-18
        • 2019-01-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多