MS SQL Pivot 来自多列的长数据
Posted
技术标签:
【中文标题】MS SQL Pivot 来自多列的长数据【英文标题】:MS SQL Pivot dat from long with multiple columns 【发布时间】:2022-01-04 09:17:12 【问题描述】:我想将具有多个 id 列的表从长转换为宽。 我找到了一列的解决方案,但不是真正的多列。 我可以适应一列的最接近的解决方案是这个 T-SQL PIVOT data from long form to wide by a date
我的桌子或多或少是这样的,
create table t (id int, date date, varA_id int, VarB_id int, value int)
insert into t values
(1,'2005-01-20',1, 1,197)
,(2,'2005-01-20',1,2,58)
,(3,'2005-01-20',1,3,90)
,(4,'2005-01-20',2,1,210)
,(5,'2005-01-20',2,2,133)
,(6,'2005-01-20',2,3,67)
,(7,'2005-01-20',3,1,87)
,(8,'2005-01-20',3,2,87)
,(9,'2005-01-20',3,3,87)
实际上没有日期,但没关系。我想以一种方式进行传播,以便为 VarA_id
和 VarB_id
的每个排列获取列
所以我的预期结果应该是这样的
我的实际表有三个 _id 列和更多排列,所以我真的需要一个通用的解决方案。
基于我链接中的其他解决方案,我希望这样的事情能够奏效。我调整了创建列名的顶部,这将起作用。我不知道如何真正调整获取值的底部。
declare @cols nvarchar(max);
declare @sql nvarchar(max);
select @cols = stuff((
select distinct
', ' + 'VarA_'+convert(varchar(10),varA_id) + '_VarB_'+convert(varchar(10),varB_id)
from t
order by 1
for xml path (''), type).value('.','nvarchar(max)')
,1,2,'')
select @sql = '
select Id, date, ' + @cols + '
from (
select Id, date, varA_id = ''v''+convert(varchar(10),varA_id), value
from t
) as t
pivot (sum([value]) for [varA_id] in (' + @cols + ') ) p'
select @sql
exec(@sql);
【问题讨论】:
预期结果确实会帮助我们帮助您,但它听起来就像您想要一个动态的支点。事实上,这最好在您的表示层中完成,而不是在数据库层中。 你的意思是在将数据提取到 R 或 Power Query 等其他软件之后? 我的意思是在任何应用程序中向最终用户显示数据;大概是某种报告软件,因为这通常是需要此类要求的原因。 我需要在 SQL 中执行此操作还有其他一些原因。我更改了数据并添加了输出图片 我假设单个日期可能有超过 9 行? 【参考方案1】:您的动态 sql 的主要问题是什么? 是源查询中构造的名称与生成的列名不匹配。
这是一个修复:
declare @cols varchar(max) = null; declare @sql nvarchar(max); select @cols = concat(@cols+', '+char(10), quotename(concat('VarA_', varA_id, '_VarB_', varB_id))) from test group by varA_id, varB_id order by varA_id, varB_id; -- select @cols as cols; set @sql = 'select * '+char(10)+ 'from ( ' +char(10)+ ' select [date], [value], ' +char(10)+ ' concat(''VarA_'',varA_id,''_VarB_'',varB_id) as Col ' +char(10)+ ' from test ' +char(10)+ ') as src ' +char(10)+ 'pivot (sum([value]) for Col in ('+char(10)+ @cols +char(10)+')) pvt'; -- select @sql as sql; exec(@sql);
date | VarA_1_VarB_1 | VarA_1_VarB_2 | VarA_1_VarB_3 | VarA_2_VarB_1 | VarA_2_VarB_2 | VarA_2_VarB_3 | VarA_3_VarB_1 | VarA_3_VarB_2 | VarA_3_VarB_3 |
---|---|---|---|---|---|---|---|---|---|
2005-01-20 | 197 | 58 | 90 | 210 | 133 | 67 | 87 | 87 | 87 |
db小提琴here
【讨论】:
我只需要更改部分来定义@cols
,我会接受你的,因为它比我的更好select @cols = stuff(( select distinct ', ' + 'VarA_'+convert(varchar(10),varA_id)+ '_VarB_' +convert(varchar(10),varB_id) from t order by 1 for xml path (''), type).value('.','nvarchar(max)') ,1,2,'')
谢谢。我刚刚注意到您使用了 DISTINCT。所以我通过添加一个 GROUP BY 来创建字段名称来更改解决方案。
啊没想到,这对我来说比其他代码更容易理解,我不太明白【参考方案2】:
到目前为止,我自己的解决方案是添加一个帮助列,基本上只是做其他问题所做的事情。我需要改进这一点,所以我不添加列,我想要更好的名字,但至少这表明了我想要的。
alter table t add help_col nvarchar(10)
Update t
set help_col=convert(varchar(10),varA_id)+convert(varchar(10),varB_id)
declare @cols nvarchar(max);
declare @sql nvarchar(max);
select @cols = stuff((
select distinct
', ' + 'v'+convert(varchar(10),help_col)
from t
order by 1
for xml path (''), type).value('.','nvarchar(max)')
,1,2,'')
select @sql = '
select date, ' + @cols + '
from (
select date, help_col = ''v''+convert(varchar(10),help_col), value
from t
) as t
pivot (sum([value]) for [help_col] in (' + @cols + ') ) p'
select @sql
exec(@sql);
结果
select date, v11, v12, v13, v21, v22, v23, v31, v32, v33 from ( select date, help_col = 'v'+convert(varchar(10),help_col), value from t ) as t pivot (sum([value]) for [help_col] in (v11, v12, v13, v21, v22, v23, v31, v32, v33) ) p
产生
date v11 v12 v13 v21 v22 v23 v31 v32 v33
2005-01-20 197 58 90 210 133 67 87 87 87
【讨论】:
以上是关于MS SQL Pivot 来自多列的长数据的主要内容,如果未能解决你的问题,请参考以下文章