将具有相同ID的多个行合并为一行

时间:2015-02-17 19:29:45

标签: sql sql-server tsql

如何将具有相同ID的多行合并为一行。

当同一列中的第一行和第二行中的值相同或第一行中有值且第二行中有NULL时。 当同一列中第一行和第二行的值不同时,我不想合并。

我有桌子:

ID |A    |B    |C
1   NULL  31    NULL
1   412   NULL  1
2   567   38    4
2   567   NULL  NULL
3   2     NULL  NULL
3   5     NULL  NULL
4   6     1     NULL
4   8     NULL  5
4   NULL  NULL  5

我想得到表:

ID |A    |B    |C
1   412   31    1
2   567   38    4
3   2     NULL  NULL
3   5     NULL  NULL
4   6     1     NULL
4   8     NULL  5
4   NULL  NULL  5

3 个答案:

答案 0 :(得分:6)

我认为上述答案的解决方案更简单(这也是正确的)。它基本上获取可以在CTE中合并的合并值,然后将其与不能合并的数据合并。

WITH CTE AS (
    SELECT
        ID,
        MAX(A) AS A,
        MAX(B) AS B,
        MAX(C) AS C
    FROM dbo.Records
    GROUP BY ID
    HAVING MAX(A) = MIN(A)
        AND MAX(B) = MIN(B)
        AND MAX(C) = MIN(C)
)
    SELECT *
    FROM CTE
    UNION ALL
    SELECT *
    FROM dbo.Records
    WHERE ID NOT IN (SELECT ID FROM CTE)

SQL小提琴:http://www.sqlfiddle.com/#!6/29407/1/0

答案 1 :(得分:3)

WITH Collapsed AS (
   SELECT
      ID,
      A = Min(A),
      B = Min(B),
      C = Min(C)
   FROM
      dbo.MyTable
   GROUP BY
      ID
   HAVING
      EXISTS (
         SELECT Min(A), Min(B), Min(C)
         INTERSECT
         SELECT Max(A), Max(B), Max(C)
      )
)
SELECT
   *
FROM
   Collapsed
UNION ALL
SELECT
   *
FROM
   dbo.MyTable T
WHERE
   NOT EXISTS (
      SELECT *
      FROM Collapsed C
      WHERE T.ID = C.ID
);

See this working in a SQL Fiddle

这可以通过使用MinMax创建所有可合并行来实现 - 对于ID中的每个列应该相同,并且有用地排除{{1} s - 然后将表中无法合并的所有行追加到此列表中。 NULL的特殊提示允许列具有EXISTS ... INTERSECT的所有NULL值(因此IDMin为{{1}并且不能相等)。也就是说,它的功能类似Max,但允许NULL s进行比较。

这是一个稍微不同(早期)的解决方案,我给出了可能提供不同的性能特征,并且更复杂,我喜欢更少,但是是一个流动的查询(没有Min(A) = Max(A) AND Min(B) = Max(B) AND Min(C) = Max(C))我更喜欢,太

NULL

这也是上面的SQL Fiddle。

这使用与第一个查询类似的逻辑来计算是否应该合并一个组,然后使用它来创建一个分组键,该键对于UNION内的所有行都是相同的,或者对于所有行中的所有行都是不同的WITH Collapsible AS ( SELECT ID FROM dbo.MyTable GROUP BY ID HAVING EXISTS ( SELECT Min(A), Min(B), Min(C) INTERSECT SELECT Max(A), Max(B), Max(C) ) ), Calc AS ( SELECT T.*, Grp = Coalesce(C.ID, Row_Number() OVER (PARTITION BY T.ID ORDER BY (SELECT 1))) FROM dbo.MyTable T LEFT JOIN Collapsible C ON T.ID = C.ID ) SELECT ID, A = Min(A), B = Min(B), C = Min(C) FROM Calc GROUP BY ID, Grp ; 。使用最终IDID也可以工作)应该合并的行被合并,因为它们共享一个分组键,而不应该合并的行不是因为它们有Min上的不同分组键。

根据您的数据集,索引,表大小和其他性能因素,这些查询中的任何一个都可能执行得更好,但第二个查询有一些工作要做,以便用两种排序而不是一种排序。

答案 2 :(得分:0)

您可以尝试这样的事情:

select 
isnull(t1.A, t2.A) as A,
isnull(t1.B, t2.B) as B,
isnull(t1.C, t2.C) as C
from
table_name t1
join table_name t2 on t1.ID = t2.ID and ..... 

你提到了第一和第二的概念。怎么办 你定义这个订单?下订单定义条件
在这里:.....

另外,我假设每个ID值只有2行。