Sql 从记录集中删除重复项(不包括重复条件中的列)

Sql 从记录集中删除重复项(不包括重复条件中的列),sql,group-by,distinct,Sql,Group By,Distinct,我遇到了一个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

我遇到了一个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行,但在停止列中被复制到,而在排除停止列中具有最低值的不幸行将被删除

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

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 ???
我需要指导,请帮忙

(不,我不能改变任何条件,我必须在给定的情况下工作。)

这应该有效:

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查询中的每一个都替换为上述内容,并更改表名

其思想是,如果存在匹配的行,但停止日期较晚,则不希望将该行包括在结果中。使用左外部联接,T2.id为NULL的唯一方式是如果没有这样的匹配,那么我们可以将其包含在结果集中(这就是为什么id必须是非NULL列才能工作的原因)


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

类似的问题也被提出和回答。例如:

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

您将从a、b和c中选择的内容放在
(…)
的位置。 只需省略
orderby
子句即可

或者,如果不是(id,type,start)->(一,二,三,四),而是(id,type,start,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)
但这取决于数据在源表中的分布方式以及存在哪些索引。在某些情况下,来自上面链接的解决方案可能仍然更好

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)