将多个不定数量的行合并为一行,每行变成多列。

huangapple go评论62阅读模式
英文:

Query for making multiple indefinite rows into one row with multiple columns

问题

我有两个表格

ID ID2
1 1
1 2
2 3
3 4
3 5

和第二个表格

ID2 Code Date1
1 A 01/01/2023
2 B 01/02/2023
3 C 01/03/2023
4 A 01/01/2023
5 D 01/15/2023

第二个表格有更多列,我需要包括,但为了简洁起见,我只包括了两列(Code和Date1)。

我需要的是基于第一个表格的ID来合并所有内容。所以它会看起来像这样

ID1 ID2-1 Code-1 Date1-1 ID2-2 Code-2 Date1-2
1 1 A 01/01/2023 2 B 01/02/2023
2 3 C 01/03/2023 NULL NULL NULL
3 4 A 01/01/2023 5 D 01/15/2023

在这些示例中,第二个表格中的一个ID最多重复两次,但第二个表格可以有无限数量与第一个表格中的ID相关联的记录。这意味着可能会有Code-10,Code-20,或者更多或更少。我需要在生成报告的一个相当大的查询中执行此操作,所以这不是最终结果中唯一的字段,但是对于特定的数据,我只使用了两个具有非常类似结构的表格,就像我在这里描述的那样。感谢任何帮助。

英文:

I have two tables

ID ID2
1 1
1 2
2 3
3 4
3 5

And the second one

ID2 Code Date1
1 A 01/01/2023
2 B 01/02/2023
3 C 01/03/2023
4 A 01/01/2023
5 D 01/15/2023

The second table has more columns that I need to include, but I'm only including two (Code and Date1) for the sake of brevity.

What I need is to unite everything based on the ID of the first table. So it would look something like

ID1 ID2-1 Code-1 Date1-1 ID2-2 Code-2 Date1-2
1 1 A 01/01/2023 2 B 01/02/2023
2 3 C 01/03/2023 NULL NULL NULL
3 4 A 01/01/2023 5 D 01/15/2023

In these examples one ID repeats up to two times in the second table, but the second table can have an indefinite amount of records tied to an ID from the first table. Meaning it might be Code-10, or Code-20, or maybe more or less. I need to do this in a pretty big query for a report I'm doing, so these are not the only fields that will be in the final result, but for this data specifically I only use two tables that have a very similar structure to the one I'm describing here. Any help will be appreciated.

答案1

得分: 2

这只是一个 SQL 代码段,不需要中文翻译。如果您需要关于此代码段的解释或有其他问题,请随时提出。

英文:

To build on T N's code, this puppy builds a "dynamic" 30 column wide pivot.


DECLARE @SQL NVARCHAR(MAX)

SET	@SQL = N'
SELECT
    A.ID
    [COLUMNS]
FROM (
    SELECT *, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ID2) AS RowNum
    FROM TableA
) A
JOIN TableB B
    ON B.ID2 = A.ID2
GROUP BY A.ID
ORDER BY A.ID'

SELECT	@SQL = REPLACE(@SQL, '[COLUMNS]', (
		SELECT	CONCAT(N'
		,	MAX(CASE WHEN A.RowNum = ',  x.sort, ' THEN B.ID2 END) AS [ID2-', x.sort, N']
		,	MAX(CASE WHEN A.RowNum = ', x.sort, ' THEN B.Code END) AS [Code-', x.sort, N']
		,	MAX(CASE WHEN A.RowNum = ', x.sort, ' THEN B.Date END) AS [Date-', x.sort, N']')
		FROM	(
			SELECT	TOP 30 row_number() OVER(ORDER BY (SELECT	NULL)) AS sort
			FROM	sys.objects so
			) x
		FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'))
SELECT	@SQL


EXEC(@SQL)

答案2

得分: 1

您可以通过使用窗口函数 ROW_NUMBER()条件聚合 的组合来实现此目标。

首先,使用 ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...) 为具有相同ID的每行分配序列号。然后将结果与您的第二个表连接,并应用 GROUP BY ID。最后,可以使用形如 MAX(CASE WHEN ... THEN .. END) 的条件聚合函数来为每列选择适当的值,将特定的行号分配给特定的列。

类似于以下代码:

SELECT
    A.ID,
    MAX(CASE WHEN A.RowNum = 1 THEN B.ID2 END) AS [ID2-1],
    MAX(CASE WHEN A.RowNum = 1 THEN B.Code END) AS [Code-1],
    MAX(CASE WHEN A.RowNum = 1 THEN B.Date END) AS [Date-1],
    MAX(CASE WHEN A.RowNum = 2 THEN B.ID2 END) AS [ID2-2],
    MAX(CASE WHEN A.RowNum = 2 THEN B Code END) AS [Code-2],
    MAX(CASE WHEN A.RowNum = 2 THEN B.Date END) AS [Date-2]
FROM (
    SELECT *, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ID2) AS RowNum
    FROM TableA
) A
JOIN TableB B
    ON B.ID2 = A.ID2
GROUP BY A.ID
ORDER BY A.ID

结果:

ID ID2-1 Code-1 Date-1 ID2-2 Code-2 Date-2
1 1 A 2023-01-01 2 B 2023-01-02
2 3 C 2023-01-03 null null null
3 4 A 2023-01-01 5 D 2023-01-15

请参考 此db<>fiddle链接

如果您需要支持每个ID的任意数量的记录而不仅仅是两条,那么您将需要涉足动态SQL的领域。

英文:

You can accomplish this by using a combination of a windowed ROW_NUMBER() number function and conditional aggregation.

First, ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...) is used to assign sequences number to each row with the same ID. The results are then be joined with your second table and a GROUP BY ID is applied. Finally, conditional aggregation functions of the form MAX(CASE WHEN ... THEN .. END) can be used to select the proper value for each column, with specific row numbers assigned to specific columns.

Something like:

SELECT
    A.ID,
    MAX(CASE WHEN A.RowNum = 1 THEN B.ID2 END) AS [ID2-1],
    MAX(CASE WHEN A.RowNum = 1 THEN B.Code END) AS [Code-1],
    MAX(CASE WHEN A.RowNum = 1 THEN B.Date END) AS [Date-1],
    MAX(CASE WHEN A.RowNum = 2 THEN B.ID2 END) AS [ID2-2],
    MAX(CASE WHEN A.RowNum = 2 THEN B.Code END) AS [Code-2],
    MAX(CASE WHEN A.RowNum = 2 THEN B.Date END) AS [Date-2]
FROM (
    SELECT *, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ID2) AS RowNum
    FROM TableA
) A
JOIN TableB B
    ON B.ID2 = A.ID2
GROUP BY A.ID
ORDER BY A.ID

Results:

ID ID2-1 Code-1 Date-1 ID2-2 Code-2 Date-2
1 1 A 2023-01-01 2 B 2023-01-02
2 3 C 2023-01-03 null null null
3 4 A 2023-01-01 5 D 2023-01-15

See this db<>fiddle.

If you need to support an arbitrary number of records per ID instead of just two, you will then need to dive into the world of dynamic SQL.

huangapple
  • 本文由 发表于 2023年2月10日 03:26:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75403500.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定