MS SQL 多列数据
MS SQL Pivot dat from long with multiple columns
我想将具有多个 id 列的 table 从长转为宽。
我为一列找到了解决方案,但没有为多列找到解决方案。
我可以为一个专栏改编的最接近的解决方案是这个
我的 table 大致是这样的,
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
的每个排列获取列
所以我的预期结果是这样的
我的实际 table 有三个 _id 列和更多排列,所以我真的需要一个通用的解决方案。
基于我 link 中的其他解决方案,我希望这样的方法能奏效。我调整了创建列名的顶部,这会起作用。我不知道如何真正调整获取值的底部。
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);
好的,到目前为止,我自己的解决方案是添加一个帮助栏,基本上只是做其他问题所做的事情。我需要对此进行改进,所以我没有添加专栏,我想要更好的名称,但至少这显示了我想要的。
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
你动态的主要问题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<>fiddle here
我想将具有多个 id 列的 table 从长转为宽。
我为一列找到了解决方案,但没有为多列找到解决方案。
我可以为一个专栏改编的最接近的解决方案是这个
我的 table 大致是这样的,
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
所以我的预期结果是这样的
我的实际 table 有三个 _id 列和更多排列,所以我真的需要一个通用的解决方案。
基于我 link 中的其他解决方案,我希望这样的方法能奏效。我调整了创建列名的顶部,这会起作用。我不知道如何真正调整获取值的底部。
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);
好的,到目前为止,我自己的解决方案是添加一个帮助栏,基本上只是做其他问题所做的事情。我需要对此进行改进,所以我没有添加专栏,我想要更好的名称,但至少这显示了我想要的。
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
你动态的主要问题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<>fiddle here