SQL Server Pivot Dynamic Sql 有两列
SQL Server Pivot Dynamic Sql with two columns
更新2022-03-04
这是我的 fiddle,显示 table 和样本值
CREATE TABLE code (
id int primary key
, labVal varchar(50)
, Label varchar(50)
)
INSERT INTO code
VALUES
(1,'Code1','Important 1')
,(2,'Code2','Important 2')
,(3,'Code3','Important 3')
CREATE TABLE client (
id int primary key
, Salary decimal
, fkCode int foreign key references code (id)
)
INSERT INTO client
VALUES (1,120,3)
,(2,1220,2)
,(3,120, 1)
;
这些是预期的结果:
id
Important 1
Salary 1
Important 2
Salary 2
Important 3
Salary 3
...
1
code1
120
NULL
NULL
NULL
NULL
...
2
NULL
NULL
code2
1220
NULL
NULL
...
3
NULL
NULL
NULL
NULL
code3
120
...
我可以使用下面的查询获得“重要 1,2,3...”的正确数据。但是我无法为“Salary1,2,3,...”插入数据,因为 pivot 只允许一系列列。
SELECT * FROM
(
SELECT
cd.id,
cd.label,
cd.labVal,
c.salary
FROM
code cd
inner join client c on c.fkcode = cd.id
) t
PIVOT(
max(labVal)
FOR label IN (
[Important 1]
,[salary1]
,[Important 2]
,[salary2]
,[Important 3]
,[salary3])
) AS pivot_table;
结果:
id | salary | Important 1 | salary1 | Important 2 | salary2 | Important 3 | salary3
-: | -----: | :---------- | :------ | :---------- | :------ | :---------- | :------
1 | 120 | Code1 | null | null | null | null | null
3 | 120 | null | null | null | null | Code3 | null
2 | 1220 | null | null | Code2 | null | null | null
原文Post:
我希望能够使用正确的数据生成此示例
------------------------------------------------------------------------------------------------
| id | whatever | important 1 | custom 1 | important 2 | custom 2 | important 3 | custom 3 |...|
|-----------------------------------------------------------------------------------------------
|x1 | a | NULL | NULL | code1 | 120 | NULL | NULL | |
------------------------------------------------------------------------------------------------
|x2 | b | code2 | 450 | NULL | NULL | NULL | NULL | |
------------------------------------------------------------------------------------------------
|x2 | b | NULL | NULL | code3 | 250 | NULL | NULL | |
------------------------------------------------------------------------------------------------
我能够获得“important1,2,3...”的正确数据,但无法插入自定义数据,因为 pivot 只允许一系列列,我无法创建两个 pivot,因为它们看起来像这样
---------------------------------------------------------------------------------------------
| id | whatever | important 1 | important2| important3 | custom 1 | custom 2 |custom 3 |
---------------------------------------------------------------------------------------------
|x | | | | | | | |
---------------------------------------------------------------------------------------------
|x | | | | | | | |
---------------------------------------------------------------------------------------------
“自定义”列是一个临时字段,其中必须包含十进制值,并且每次显示“重要”列时都会重复。
“重要”列 header 来自 table,其中包含我使用 pivot 从行转换为列并从不同列分配所需值的名称。
但是自定义列在任何 table 中都不存在,但我想放入其中的值确实存在,问题是,我正在使用动态 sql 生成“自定义”列名称使用 row_number 以避免重复列错误。
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT ',' + QUOTENAME(c.important) +','+ QUOTENAME( 'custom' + CAST(ROW_NUMBER() OVER (ORDER BY c.id) as VARCHAR)) as tempfield
FROM tableName rp
inner join tblsecond c on rp.sTbId = c.id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
print @cols
----- this @cols
---- will print [important first row to column],[custom1],[important second row to column],[custom2]..
set @query = 'SELECT * into #temp from
(
select c.id, c.whatever, c.name, c.customColumnValue
FROM tableName rp
inner join tblsecond c on rp.sTbId = c.id
) x
pivot
(
max(name)
for important in (' + @cols +')
) p select * from #temp
'
execute(@query)
示例数据在这里
我认为您将需要多个 PIVOT。一些事情使它变得稍微复杂一些
- Code/Label 列 未 按顺序命名
CodeX,CodeY,...
- 工资列 按顺序命名
Salary1,Salary2,...
- SELECT 列表列必须组合在一起
"CodeX,Salary1,CodeY,Salary2....*
SET @cols = STUFF((SELECT ',' + QUOTENAME(c.important) +','+ QUOTENAME( 'custom' + CAST(ROW_NUMBER() OVER (ORDER BY c.id) as VARCHAR))
您的想法是正确的,构建了一个包含两列的串联列表。但是您实际上需要 3 个变量:1) 对于代码列 2) 对于工资列和 3) 对于 select 列表。
注意:必须在所有查询中使用相同的 ORDER BY
DECLARE @LabelCols AS VARCHAR(MAX),
@SalaryCols AS VARCHAR(MAX),
@SelectCols AS VARCHAR(MAX),
@Query AS VARCHAR(MAX);
-- ** SQL Server 2012 doesn't support STRING_AGG()
SET @LabelCols = STUFF(( SELECT ',' + QUOTENAME(cd.label)
FROM code cd INNER JOIN client c ON c.fkcode = cd.id
ORDER BY cd.id
FOR XML PATH('')
),1,1,'')
SET @SalaryCols = STUFF(( SELECT ',' + QUOTENAME('Salary'+
CAST(ROW_NUMBER() OVER (ORDER BY cd.id) AS VARCHAR(20))
)
FROM code cd INNER JOIN client c ON c.fkcode = cd.id
FOR XML PATH('')
),1,1,'')
SET @SelectCols = STUFF(( SELECT ',' + QUOTENAME(cd.label)
+ ',' + QUOTENAME('Salary'+
CAST(ROW_NUMBER() OVER (ORDER BY cd.id) AS VARCHAR(20)))
FROM code cd INNER JOIN client c ON c.fkcode = cd.id
FOR XML PATH('')
),1,1,'')
然后在你的SELECT中使用三个变量:
SET @Query = '
SELECT ClientId
, CodeId
, '+ @SelectCols +'
FROM
(
SELECT cd.id AS CodeId
, cd.label
, cd.labVal
, c.salary
, ''Salary''+ CAST(ROW_NUMBER() OVER (ORDER BY c.id) AS VARCHAR(20)) AS salaryLabel
FROM code cd
INNER JOIN client c ON c.fkcode = cd.id
) x
PIVOT
(
MAX(labVal)
FOR label IN (' + @LabelCols +')
) p1
PIVOT
(
MAX(salary)
FOR salaryLabel IN (' + @SalaryCols +')
) p2
'
EXECUTE (@Query)
结果:
CodeId | Important 1 | Salary1 | Important 2 | Salary2 | Important 3 | Salary3
-----: | :---------- | ------: | :---------- | ------: | :---------- | ------:
1 | Code1 | 120 | null | null | null | null
2 | null | null | Code2 | 1220 | null | null
3 | null | null | null | null | Code3 | 120
db<>fiddle here
更新2022-03-04
这是我的 fiddle,显示 table 和样本值
CREATE TABLE code ( id int primary key , labVal varchar(50) , Label varchar(50) ) INSERT INTO code VALUES (1,'Code1','Important 1') ,(2,'Code2','Important 2') ,(3,'Code3','Important 3') CREATE TABLE client ( id int primary key , Salary decimal , fkCode int foreign key references code (id) ) INSERT INTO client VALUES (1,120,3) ,(2,1220,2) ,(3,120, 1) ;
这些是预期的结果:
id | Important 1 | Salary 1 | Important 2 | Salary 2 | Important 3 | Salary 3 | ... |
---|---|---|---|---|---|---|---|
1 | code1 | 120 | NULL | NULL | NULL | NULL | ... |
2 | NULL | NULL | code2 | 1220 | NULL | NULL | ... |
3 | NULL | NULL | NULL | NULL | code3 | 120 | ... |
我可以使用下面的查询获得“重要 1,2,3...”的正确数据。但是我无法为“Salary1,2,3,...”插入数据,因为 pivot 只允许一系列列。
SELECT * FROM
(
SELECT
cd.id,
cd.label,
cd.labVal,
c.salary
FROM
code cd
inner join client c on c.fkcode = cd.id
) t
PIVOT(
max(labVal)
FOR label IN (
[Important 1]
,[salary1]
,[Important 2]
,[salary2]
,[Important 3]
,[salary3])
) AS pivot_table;
结果:
id | salary | Important 1 | salary1 | Important 2 | salary2 | Important 3 | salary3 -: | -----: | :---------- | :------ | :---------- | :------ | :---------- | :------ 1 | 120 | Code1 | null | null | null | null | null 3 | 120 | null | null | null | null | Code3 | null 2 | 1220 | null | null | Code2 | null | null | null
原文Post:
我希望能够使用正确的数据生成此示例
------------------------------------------------------------------------------------------------
| id | whatever | important 1 | custom 1 | important 2 | custom 2 | important 3 | custom 3 |...|
|-----------------------------------------------------------------------------------------------
|x1 | a | NULL | NULL | code1 | 120 | NULL | NULL | |
------------------------------------------------------------------------------------------------
|x2 | b | code2 | 450 | NULL | NULL | NULL | NULL | |
------------------------------------------------------------------------------------------------
|x2 | b | NULL | NULL | code3 | 250 | NULL | NULL | |
------------------------------------------------------------------------------------------------
我能够获得“important1,2,3...”的正确数据,但无法插入自定义数据,因为 pivot 只允许一系列列,我无法创建两个 pivot,因为它们看起来像这样
---------------------------------------------------------------------------------------------
| id | whatever | important 1 | important2| important3 | custom 1 | custom 2 |custom 3 |
---------------------------------------------------------------------------------------------
|x | | | | | | | |
---------------------------------------------------------------------------------------------
|x | | | | | | | |
---------------------------------------------------------------------------------------------
“自定义”列是一个临时字段,其中必须包含十进制值,并且每次显示“重要”列时都会重复。
“重要”列 header 来自 table,其中包含我使用 pivot 从行转换为列并从不同列分配所需值的名称。 但是自定义列在任何 table 中都不存在,但我想放入其中的值确实存在,问题是,我正在使用动态 sql 生成“自定义”列名称使用 row_number 以避免重复列错误。
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SET @cols = STUFF((SELECT ',' + QUOTENAME(c.important) +','+ QUOTENAME( 'custom' + CAST(ROW_NUMBER() OVER (ORDER BY c.id) as VARCHAR)) as tempfield
FROM tableName rp
inner join tblsecond c on rp.sTbId = c.id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
print @cols
----- this @cols
---- will print [important first row to column],[custom1],[important second row to column],[custom2]..
set @query = 'SELECT * into #temp from
(
select c.id, c.whatever, c.name, c.customColumnValue
FROM tableName rp
inner join tblsecond c on rp.sTbId = c.id
) x
pivot
(
max(name)
for important in (' + @cols +')
) p select * from #temp
'
execute(@query)
示例数据在这里
我认为您将需要多个 PIVOT。一些事情使它变得稍微复杂一些
- Code/Label 列 未 按顺序命名
CodeX,CodeY,...
- 工资列 按顺序命名
Salary1,Salary2,...
- SELECT 列表列必须组合在一起
"CodeX,Salary1,CodeY,Salary2....*
SET @cols = STUFF((SELECT ',' + QUOTENAME(c.important) +','+ QUOTENAME( 'custom' + CAST(ROW_NUMBER() OVER (ORDER BY c.id) as VARCHAR))
您的想法是正确的,构建了一个包含两列的串联列表。但是您实际上需要 3 个变量:1) 对于代码列 2) 对于工资列和 3) 对于 select 列表。
注意:必须在所有查询中使用相同的 ORDER BY
DECLARE @LabelCols AS VARCHAR(MAX),
@SalaryCols AS VARCHAR(MAX),
@SelectCols AS VARCHAR(MAX),
@Query AS VARCHAR(MAX);
-- ** SQL Server 2012 doesn't support STRING_AGG()
SET @LabelCols = STUFF(( SELECT ',' + QUOTENAME(cd.label)
FROM code cd INNER JOIN client c ON c.fkcode = cd.id
ORDER BY cd.id
FOR XML PATH('')
),1,1,'')
SET @SalaryCols = STUFF(( SELECT ',' + QUOTENAME('Salary'+
CAST(ROW_NUMBER() OVER (ORDER BY cd.id) AS VARCHAR(20))
)
FROM code cd INNER JOIN client c ON c.fkcode = cd.id
FOR XML PATH('')
),1,1,'')
SET @SelectCols = STUFF(( SELECT ',' + QUOTENAME(cd.label)
+ ',' + QUOTENAME('Salary'+
CAST(ROW_NUMBER() OVER (ORDER BY cd.id) AS VARCHAR(20)))
FROM code cd INNER JOIN client c ON c.fkcode = cd.id
FOR XML PATH('')
),1,1,'')
然后在你的SELECT中使用三个变量:
SET @Query = '
SELECT ClientId
, CodeId
, '+ @SelectCols +'
FROM
(
SELECT cd.id AS CodeId
, cd.label
, cd.labVal
, c.salary
, ''Salary''+ CAST(ROW_NUMBER() OVER (ORDER BY c.id) AS VARCHAR(20)) AS salaryLabel
FROM code cd
INNER JOIN client c ON c.fkcode = cd.id
) x
PIVOT
(
MAX(labVal)
FOR label IN (' + @LabelCols +')
) p1
PIVOT
(
MAX(salary)
FOR salaryLabel IN (' + @SalaryCols +')
) p2
'
EXECUTE (@Query)
结果:
CodeId | Important 1 | Salary1 | Important 2 | Salary2 | Important 3 | Salary3 -----: | :---------- | ------: | :---------- | ------: | :---------- | ------: 1 | Code1 | 120 | null | null | null | null 2 | null | null | Code2 | 1220 | null | null 3 | null | null | null | null | Code3 | 120
db<>fiddle here