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

Merge multiple rows with same ID into one row

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

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

我有 table:

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

我想得到table:

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

您可以尝试这样的操作:

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 行。

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 中的每一列应该是相同的并且有用地排除 NULLs--然后将 table 中无法合并的所有行附加到此列表。 EXISTS ... INTERSECT 的特殊技巧允许列具有 ID 的所有 NULL 值的情况(因此 MinMaxNULL 并且不能彼此相等)。也就是说,它的功能类似于 Min(A) = Max(A) AND Min(B) = Max(B) AND Min(C) = Max(C),但允许 NULL 进行比较。

这是我给出的一个稍微不同的(较早的)解决方案,它可能提供不同的性能特征,而且更复杂,我不太喜欢,但作为一个单一的流动查询(没有 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
;

这个也在上面SQLFiddle.

这使用与第一个查询类似的逻辑来计算是否应合并一个组,然后使用它来创建一个分组键,该键对于 ID 中的所有行都相同,或者对于所有行都不同ID 内的行。使用最终的 MinMax 也可以)应该合并的行被合并,因为它们共享一个分组键,而不应该合并的行不是因为它们有ID.

上的不同分组键

根据您的数据集、索引、table 大小和其他性能因素,这些查询中的任何一个都可能执行得更好,尽管第二个查询需要做一些工作才能赶上,但有两种查询一个。

我认为上述答案有更简单的解决方案(这也是正确的)。它基本上获取可以在 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 Fiddle: http://www.sqlfiddle.com/#!6/29407/1/0