Отключить данные, сохранив одну строку в качестве столбца - PullRequest
0 голосов
/ 01 октября 2019

У меня есть следующие данные, которые я пытаюсь отменить. Количество столбцов, с которыми я имею дело, простирается до F600

enter image description here

В основном данные строки SEQ_NUM становятся столбцом с именем SEQ_NUM, а ячейки остаются столбцомно без строки SEQ_NUM и нового столбца «NewCol» будет содержать данные содержимого, за исключением данных строки SEQ_NUM, которые теперь являются столбцами.

Я хочу получить этот формат. Теперь я могу сделать с помощью UNION ALL и циклического перемещения курсора по всем столбцам от F2 до F600 и перекрестного соединения с данными из SEQ_NUM, но я думаю, что есть лучшее решение.

enter image description here

Ответы [ 2 ]

0 голосов
/ 02 октября 2019

Наихудший сценарий, вы можете сделать это долго:

select b.f2 as newcol, b.cells, a.f2 as seq_num from t a cross join t b where a.cells = 'SEQ_Num' and b.cells <> 'SEQ_Num'
union select b.f3, b.cells, a.f3 from t a cross join t b where a.cells = 'SEQ_Num' and b.cells <> 'SEQ_Num'
union select b.f4, b.cells, a.f4 from t a cross join t b where a.cells = 'SEQ_Num' and b.cells <> 'SEQ_Num'
union select b.f5, b.cells, a.f5 from t a cross join t b where a.cells = 'SEQ_Num' and b.cells <> 'SEQ_Num'
union select b.f6, b.cells, a.f6 from t a cross join t b where a.cells = 'SEQ_Num' and b.cells <> 'SEQ_Num'
union select b.f7, b.cells, a.f7 from t a cross join t b where a.cells = 'SEQ_Num' and b.cells <> 'SEQ_Num'
union select b.f8, b.cells, a.f8 from t a cross join t b where a.cells = 'SEQ_Num' and b.cells <> 'SEQ_Num'
union select b.f9, b.cells, a.f9 from t a cross join t b where a.cells = 'SEQ_Num' and b.cells <> 'SEQ_Num'
union select b.f10, b.cells, a.f10 from t a cross join t b where a.cells = 'SEQ_Num' and b.cells <> 'SEQ_Num'
union select b.f18, b.cells, a.f18 from t a cross join t b where a.cells = 'SEQ_Num' and b.cells <> 'SEQ_Num'
order by seq_num, cells

Не мило, но выполняет свою работу.

0 голосов
/ 02 октября 2019

Версия ваших данных, с которой можно работать, выглядит следующим образом:

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 не ясна, хотя вы, вероятно,хочу переформатировать это.

...