を使用した非常に優れたアプローチがあるの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
)
この CTEFlattenedInput
が利用可能になったので、あとは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>
任意のサイズの「正方形」データで動作します。健全性チェック/エラー処理の欠如に注意してください。