Версия ваших данных, с которой можно работать, выглядит следующим образом:
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);
Edit: учет 'seq_num' не является простым смещением заголовков полей
Хорошо, вы говорите, что seq_num - это не просто смещение имен столбцов. Представьте, что мы поменяли строку seq_num на вставке таблицы следующим образом:
insert #t values
('seq_num', 2, 4, 8),
...
Вам придется в значительной степени отделить его от остальных строк и обработать его независимо. Но к счастью, вы действуете параллельно. То есть, так же как и мой запрос выше, откручивает данные для cells <> 'seq_num'
, вы делаете то же самое, за исключением cells = 'seq_num'
. Вам нужно соединить два набора результатов вместе, поэтому выведите в каждом из них непивотированный ярлык поля.
Замените приведенную выше переменную @sql следующим образом:
declare @sql nvarchar(max) = '
select up.cells,
up.col,
up.val
from #t
unpivot (val for col in (' + @cols + ')) up
where cells @operator ''seq_num''
';
Обратите внимание, что я вывожу вверх.col, вместо того, чтобы изменять его, и я также заменяю '<>' на '@operator'. В отличие от @cols
, @operator является частью окружающей строки.
В данный момент @sql действует как шаблон. Используйте его, чтобы создать один экземпляр для ячеек, равных 'seq_num', и один для ячеек, не равных 'seq_num'. Эти экземпляры должны быть в своих собственных выражениях CTE, которые вы впоследствии повторно присоедините в последнем утверждении. Замените существующую переменную @sql этим оператором, а затем выполните его, как показано ниже:
set @sql = '
with
linkVals as (' + replace(@sql, '@operator', '<>') + '),
seqVals as (' + replace(@sql, '@operator', '=') + ')
select l.cells,
seq_num = s.val,
l.val
from linkVals l
join seqVals s on l.col = s.col
';
print (@sql);
exec (@sql);
Я вставляю оператор печати на случай, если окончательная форма @sql не ясна, хотя вы, вероятно,хочу переформатировать это.