英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论