将具有相同 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
这是通过使用 Min
和 Max
创建所有可合并的行来实现的——这对于 ID
中的每一列应该是相同的并且有用地排除 NULL
s--然后将 table 中无法合并的所有行附加到此列表。 EXISTS ... INTERSECT
的特殊技巧允许列具有 ID
的所有 NULL
值的情况(因此 Min
和 Max
是 NULL
并且不能彼此相等)。也就是说,它的功能类似于 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
内的行。使用最终的 Min
(Max
也可以)应该合并的行被合并,因为它们共享一个分组键,而不应该合并的行不是因为它们有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
如何将具有相同 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
这是通过使用 Min
和 Max
创建所有可合并的行来实现的——这对于 ID
中的每一列应该是相同的并且有用地排除 NULL
s--然后将 table 中无法合并的所有行附加到此列表。 EXISTS ... INTERSECT
的特殊技巧允许列具有 ID
的所有 NULL
值的情况(因此 Min
和 Max
是 NULL
并且不能彼此相等)。也就是说,它的功能类似于 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
内的行。使用最终的 Min
(Max
也可以)应该合并的行被合并,因为它们共享一个分组键,而不应该合并的行不是因为它们有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