t-sql 最有效的行到列? xml 路径、枢轴的交叉表

发布于 2024-08-28 22:48:32 字数 2643 浏览 8 评论 0原文

我正在寻找将行转换为列的最有效的方法。我需要以固定宽度和分隔格式输出数据库的内容(不是下面的实际模式,但概念相似)。下面的 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

输出我想要的内容,但是对于大量数据来说速度非常慢。其中一个子表超过 200 万行,将处理时间延长至约 4 小时。

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

I am looking for the most performant way to turn rows into columns. I have a requirement to output the contents of the db (not actual schema below, but concept is similar) in both fixed width and delimited formats. The below FOR XML PATH query gives me the result I want, but when dealing with anything other than small amounts of data, can take awhile.

 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

I've looked at pivot but most of the examples I have found are aggregating information. I just want to combine the child rows and tack them onto the parent.

I should also point out I don't need to deal with the column names either since the output of the child rows will either be a fixed width string or a delimited string.

For example, given the following tables:

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

for an order I need to output:

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

or

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

Thoughts or suggestions? I am using SQL Server 2k5.

Example Setup:

   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)

using 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

which outputs what I want, however is very slow for large amounts of data. One of the child tables is over 2 million rows, pushing the processing time out to ~ 4 hours.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

°如果伤别离去 2024-09-04 22:48:32

根据定义,数据透视表必须以某种方式聚合,因为您可以拥有具有相同数据透视表键列的多行。如果您没有多行,那很好 - 但您仍然需要选择聚合运算符(MIN、MAX、SUM)。

但是 FOR XML PATH 构造更适合多行值到单字符串列的“透视”操作。

我不确定为什么你的表现不好。表上有哪些索引?您的执行计划是什么样的?

By definition a PIVOT is going to HAVE to aggregate in some way, because you can have multiple rows with the same pivot key columns. If you don't have multiple rows, that's fine - but you still need to choose an aggregate operator (MIN, MAX, SUM).

But the FOR XML PATH construct is better for the multiple-row-values to single-string-column "pivot" operation.

I'm not sure why yours is not performing well. What indexes do you have on the tables? What does your execution plan look like?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文