Home > OS >  MS SQL Pivot dat from long with multiple columns
MS SQL Pivot dat from long with multiple columns

Time:11-26

I want to pivot a table from long to wide that has multiple id columns. I found solutions for one column but not really for multiple columns. The closest solution that I could adapt for one column was this one enter image description here

My actual table has three _id columns and more permutations, so I really need a generic solution.

Based on the other solution in my link I was hoping something like this would work. I adjust the top part that creates the column names and this would work. I dont know how to realy adjust the bottom part that fetches the values.

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);

CodePudding user response:

The main problem with your dynamic sql?
It was that the name constructed in the source query didn't match the generated column names.

Here's a fix :

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

CodePudding user response:

Ok my own solution so far is to add a help column and basically just do what the other questions does. I need to improve on this, so I dont add a column and I would like better names, but at least this shows what I want.

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);

Which results in

   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

which yields

date        v11 v12 v13 v21 v22 v23 v31 v32 v33
2005-01-20  197 58  90  210 133 67  87  87  87
  • Related