取消数据保留一行作为列

问题描述 投票:0回答:1

我具有以下数据,我试图取消这些数据。我正在处理的列数一直到F600

enter image description here

基本上,SEQ_NUM行数据成为名为SEQ_NUM的列,而Cells仍为列,但没有SEQ_NUM行,新列“ NewCol”将具有内容数据,而SEQ_NUM行数据现在是一列。

我想获得这种格式。现在,我可以使用UNION ALL并通过游标遍历从F2到F600的所有列,并与SEQ_NUM的数据交叉联接,但是我认为有更好的解决方案。

enter image description here

sql sql-server unpivot cross-join
1个回答
0
投票

可以使用的数据版本如下:

create table #t (cells varchar(15), f2 int, f3 int, f4 int);

insert #t values 
    ('seq_num', 1, 2, 3), 
    ('linkA', 4290, 42521, 42551),
    ('linkB', 0, 0, 0),
    ('linkC', 1332, 0, 15);

正如avery_larry所提到的,这似乎是基本原理。我认为您可能会被甩掉的是'seq_num'与列名是多余的。列“ f2”至“ f600”已经按顺序排列。因此,只需取消透视,即可从透视列标签中提取整数,然后减去一个。在执行所有这些操作时,请忽略“ seq_num”行。

select      up.cells,
            seq_num = try_convert(int,replace(up.col, 'f', '')) - 1,
            up.val
from        #t
unpivot     (val for col in (f2, f3, f4)) up -- you write out to 'f600'
where       cells <> 'seq_num';

[如果您希望避免将'f2'写到'f600',则可以动态进行。首先构建包含所有列名称的字符串,然后将其插入“ in”语句中。

declare 
    @cols varchar(max) = '',
    @f int = 1,
    @maxF int = 4; -- you change to 600

while @f < @maxF begin
    set @f += 1;
    set @cols += 'f' + convert(varchar(3), @f) + iif(@f <> @maxF, ',', '');
end

declare @sql nvarchar(max) = '
    select      up.cells,
                seq_num = try_convert(int,replace(up.col, ''f'', '''')) - 1,
                up.val
    from        #t
    unpivot     (val for col in (' + @cols + ')) up
    where       cells <> ''seq_num''
';

 exec (@sql);
© www.soinside.com 2019 - 2024. All rights reserved.