Я подозреваю, что может быть действительно хороший подход с использованием PIVOT
, но я не знаю этого достаточно хорошо, чтобы сказать наверняка. То, что я предлагаю здесь, работает. Я разделил его на куски для лучшего форматирования и предоставления комментариев:
Для начала давайте захватим данные примера
-- Sample data
DECLARE @x3 xml
SET @x3 = '
<root>
<row>
<column>row 1 col 1</column>
<column>row 1 col 2</column>
<column>row 1 col 3</column>
</row>
<row>
<column>row 2 col 1</column>
<column>row 2 col 2</column>
<column>row 2 col 3</column>
</row>
<row>
<column>row 3 col 1</column>
<column>row 3 col 2</column>
<column>row 3 col 3</column>
</row>
</root>
'
DECLARE @x xml
SET @x = @x3
-- @x is now our input
Теперь актуальный код транспонирования:
Установить размер матрицы:
WITH Size(Size) AS
(
SELECT CAST(SQRT(COUNT(*)) AS int)
FROM @x.nodes('/root/row/column') T(C)
)
Измельчите данные, используйте ROW_NUMBER
для захвата индекса (-1
должен сделать его основанным на нуле), и используйте деление по модулю и целому числу для индекса, чтобы обработать новую строку * * номера столбцов:
,Flattened(NewRow, NewCol, Value) AS
(
SELECT
-- i/@size as old_r, i % @size as old_c,
i % (SELECT TOP 1 Size FROM Size) AS NewRow,
i / (SELECT TOP 1 Size FROM Size) AS NewCol,
Value
FROM (
SELECT
(ROW_NUMBER() OVER (ORDER BY C)) - 1 AS i,
C.value('.', 'nvarchar(100)') AS Value
FROM @x.nodes('/root/row/column') T(C)
) ShreddedInput
)
Имея этот CTE FlattenedInput
, все, что нам теперь нужно сделать, - это правильно настроить параметры и структуру запросов FOR XML
, и все готово:
SELECT
(
SELECT Value 'column'
FROM
Flattened t_inner
WHERE
t_inner.NewRow = t_outer.NewRow
FOR XML PATH(''), TYPE
) row
FROM
Flattened t_outer
GROUP BY NewRow
FOR XML PATH(''), ROOT('root')
Пример вывода:
<root>
<row>
<column>row 1 col 1</column>
<column>row 2 col 1</column>
<column>row 3 col 1</column>
</row>
<row>
<column>row 1 col 2</column>
<column>row 2 col 2</column>
<column>row 3 col 2</column>
</row>
<row>
<column>row 1 col 3</column>
<column>row 2 col 3</column>
<column>row 3 col 3</column>
</row>
</root>
Работает с «квадратными» данными любого размера. Обратите внимание на отсутствие проверки работоспособности / обработки ошибок.