1

行を列に変換する最も効率的な方法を探しています。データベースの内容 (以下の実際のスキーマではありませんが、概念は似ています) を固定幅形式と区切り形式の両方で出力する必要があります。以下の FOR XML PATH クエリでは、必要な結果が得られますが、少量のデータ以外を処理する場合は、時間がかかることがあります。

 select orderid
   ,REPLACE((  SELECT '  ' + CAST(ProductId as varchar)
       FROM _details d
       WHERE d.OrderId = o.OrderId
       ORDER BY d.OrderId,d.DetailId
       FOR XML PATH('')
   ),' ','') as Products
 from _orders o

ピボットを見てきましたが、見つけた例のほとんどは情報を集約しています。子行を結合して親に追加したいだけです。

また、子行の出力は固定幅の文字列または区切り文字列のいずれかになるため、列名を処理する必要がないことも指摘しておく必要があります。

たとえば、次の表があるとします。

OrderId     CustomerId
----------- -----------
1           1
2           2
3           3

DetailId    OrderId     ProductId
----------- ----------- -----------
1           1           100
2           1           158
3           1           234
4           2           125
5           3           101
6           3           105
7           3           212
8           3           250

出力する必要がある注文の場合:

orderid     Products
----------- -----------------------
1             100  158  234
2             125
3             101  105  212  250

また

orderid     Products
----------- -----------------------
1           100|158|234
2           125
3           101|105|212|250

考えや提案はありますか?SQL Server 2k5 を使用しています。

セットアップ例:

   create table _orders (
  OrderId int identity(1,1) primary key nonclustered
  ,CustomerId int
 )

 create table _details (
  DetailId int identity(1,1) primary key nonclustered
  ,OrderId int 
  ,ProductId int
 )

 insert into _orders (CustomerId)
 select 1
 union select 2
 union select 3

 insert into _details (OrderId,ProductId)
 select 1,100
 union select 1,158
 union select 1,234
 union select 2,125
 union select 3,105
 union select 3,101
 union select 3,212
 union select 3,250

 CREATE CLUSTERED INDEX IX_CL__orders on _orders(OrderId)
 CREATE NONCLUSTERED INDEX IX_NCL__orders on _orders(OrderId)
 INCLUDE (CustomerId)

 CREATE CLUSTERED INDEX IX_CL_details on _details(OrderId)
 CREATE NONCLUSTERED INDEX IX_NCL_details on _details(OrderId)
 INCLUDE (DetailId,ProductId)

FOR XML PATH を使用:

 select orderid
   ,REPLACE((  SELECT '  ' + CAST(ProductId as varchar)
       FROM _details d
       WHERE d.OrderId = o.OrderId
       ORDER BY d.OrderId,d.DetailId
       FOR XML PATH('')
   ),' ','') as Products
 from _orders o

私が望むものを出力しますが、大量のデータの場合は非常に遅くなります。子テーブルの 1 つが 200 万行を超えているため、処理時間が最大 4 時間かかります。

orderid     Products
----------- -----------------------
1             100  158  234
2             125
3             101  105  212  250
4

1 に答える 1

1

定義上、PIVOT は何らかの方法で集約する必要があります。これは、同じピボット キー列を持つ複数の行を持つことができるためです。複数の行がない場合は問題ありませんが、集計演算子 (MIN、MAX、SUM) を選択する必要があります。

ただし、このFOR XML PATH構造は、複数の行の値から単一の文字列の列への「ピボット」操作に適しています。

なぜあなたのパフォーマンスが良くないのかわかりません。テーブルにはどのようなインデックスがありますか? 実行計画はどのようになっていますか?

于 2010-04-12T21:13:58.413 に答える