繁体   English   中英

SQL Server:将行转换为列(枢轴,但有所不同)

[英]SQL Server : turning rows into columns (pivot, but with a twist)

我正在尝试将表的多行压缩为1行但多列。

我看了几种方法,但是似乎没有一种方法适合我的需求。 (主要)问题是表中没有“标题”数据,这破坏了数据透视方法。

基本上,我有2个表要加入,我只想获取前3个项目(超过3个我不在乎)。

因此,我的2个表已创建并填充。

CREATE TABLE [order] ( ID INT )
CREATE TABLE OrderItem ( OrderID INT, Item VARCHAR(20) )

insert into [order] values (1)
insert into [order] values (2)

insert into orderitem values (1, 'Hammer')
insert into orderitem values (2, 'Spoon')
insert into orderitem values (2, 'Potato')
insert into orderitem values (2, 'shed')

我想要这样的结果:

ID  Item1   Item2   Item3  
1   Hammer  NULL    NULL  
2   Potato  shed    Spoon  

我研究了几种使用PIVOT方法,但是由于每个值没有任何“标题”,并且[OrderItem]中有成千上万个唯一的[Item]值,我无法弄清楚如何获取查询以执行我想要的操作。

我设法通过一些难看的排名联接来做到这一点的唯一方法-效果很好,但速度慢得令人难以置信

(没有联接的查询需要花费一秒钟的时间才能完成,但是由于要查看的数据量大,一旦包含这些查询,则需要花费2-3分钟的时间)

SELECT 
    o.ID, i1.Item, i2.Item, i3.Item 
FROM
    [order] o
LEFT OUTER JOIN
    (SELECT
         *, 
         RANK() OVER (PARTITION BY orderId ORDER BY item) AS iRank
     FROM 
         OrderItem) AS i1 ON i1.OrderID = o.ID AND i1.iRank = 1
LEFT OUTER JOIN
    (SELECT
         *, 
         RANK() OVER (PARTITION BY orderId ORDER BY item) AS iRank
     FROM 
         OrderItem) AS i2 ON i2.OrderID = o.ID AND i2.iRank = 2
LEFT OUTER JOIN
    (SELECT
         *, 
         RANK() OVER (PARTITION BY orderId ORDER BY item) AS iRank
     FROM 
         OrderItem) AS i3 ON i3.OrderID = o.ID AND i2.iRank = 3

谁能推荐一种更好的方法来查看它,使其在运行时不会完全杀死我的数据库?

尽管您可以使用pivot做到这一点,但仅使用条件聚合可能会更容易:

select oi.OrderId,
       max(case when iRank = 1 then oi.Item end) as item1,
       max(case when iRank = 2 then oi.Item end) as item2,
       max(case when iRank = 3 then oi.Item end) as item3
from (select oi.*,
             rank() over (partition by orderId order by item) as iRank
      from OrderItem oi
     ) oi 
group by oi.OrderId;

更新-由于订单项的数量不确定,我将其转换为动态PIVOT

DECLARE @qu NVARCHAR(MAX), @pcol NVARCHAR(MAX)
SELECT   @pcol= COALESCE(@pcol + ',','') + ItemNumber FROM
 (SELECT DISTINCT N'Item'+ CAST (ROW_NUMBER() OVER(PARTITION BY OrderID Order by Item) AS NVARCHAR(25)) AS ItemNumber 
  FROM OrderItem) A

SET @qu=N'SELECT OrderId,'+ @pcol + N' FROM 
(
  SELECT 
  OrderID,N''Item''+ CAST (ROW_NUMBER() OVER(PARTITION BY OrderID Order by Item) AS NVARCHAR(25)) AS ItemNumber, Item FROM OrderItem
  )S
  PIVOT
  (
  MAX(Item) 
    FOR ItemNumber IN ('+@pcol +N')) AS piv'
EXEC sp_executesql @qu

更新SQL小提琴链接: http ://sqlfiddle.com/#!6/ 0cd9d0/17

编辑-原始答案:

将Pivot用于已知的最大订单项数,这可以像

 SELECT OrderId,[Item1],[Item2],[Item3],[Item4],[Item5],[Item6] FROM ( SELECT OrderID,N'Item'+ CAST (ROW_NUMBER() OVER(PARTITION BY OrderID Order by Item) AS NVARCHAR(25)) AS ItemNumber, Item FROM OrderItem )S PIVOT ( MAX(Item) FOR ItemNumber IN ([Item1],[Item2],[Item3],[Item4],[Item5],[Item6]) )piv 

SQL小提琴链接: http ://sqlfiddle.com/#!6/0cd9d0/4

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM