显示每个用户的订购商品

时间:2019-05-14 09:06:07

标签: sql-server

我有以下内容:

customerID | OrderID | OrderPosition | Articlenumber|
-----------+---------+---------------+--------------+
101        | 1       | 1             | 123          |
101        | 1       | 2             | 799          |
102        | 2       | 1             | 111          |
103        | 3       | 1             | 456          |
101        | 4       | 1             | 789          |
103        | 5       | 1             | 444          |
103        | 5       | 2             | 999          |
101        | 6       | 1             | 555          |
101        | 6       | 2             | 777          |
101        | 6       | 3             | 222          |

并且我想要以下内容(每个客户ID最多汇总4篇文章(按orderID(从高到低排序)和OrderPosition(从低到低)排序):

customerID |articelnumber 1|articelnumber 2|articelnumber 3|articelnumber 4|
-------+-------------------+---------------+---------------+---------------+
101        |555            |777            |222            | 789           |
102        |111            |NULL           |NULL           |NULL           |
103        |444            |999            |456            |NULL           |

像这样尝试过,但这不能正常工作:

select *
from 
(
select customerid, OrderID , OrderPosition, Articlenumber FROM table
) src
pivot
(
  avg (Articlenumber)
  for OrderPosition in ([articelnumber 1], [articelnumber 2], [articelnumber 3], [articelnumber 4])
) piv

3 个答案:

答案 0 :(得分:1)

我花了一些时间才能获得与您期望的输出相同的结果,但最终我设法做到了:

if exists (select 1 from sysobjects where name = 'TempTable')
drop table TempTable;

if exists (select 1 from sysobjects where name = 'TempTable2')
drop table TempTable2;

declare @cols   nvarchar(max)
,       @cols2  nvarchar(max)
,       @sql  nvarchar(max)
,       @loop   int;

create table TempTable (id int primary key identity, CustomerID int, OrderID int, OrderPosition int, ArticleNumber int)

insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,1,1,123)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,1,2,799)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (102,2,1,111)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (103,3,1,456)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,4,1,789)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (103,5,1,444)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (103,5,2,999)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,6,1,555)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,6,2,777)
insert into TempTable (CustomerID, OrderID, OrderPosition, ArticleNumber) values (101,6,3,222);

create table TempTable2 (CustomerID int, OrderID int, OrderPosition int, ArticleNumber int, ArticleDesc varchar(100))

select @loop = min(id) from TempTable
while @loop is not null

begin
    set @sql    = ' insert into TempTable2 (CustomerID, OrderID, OrderPosition, ArticleNumber, ArticleDesc)
                    select top 4 CustomerID, OrderID, OrderPosition, ArticleNumber, ''ArticleNumber ''+cast(rank() over (order by orderID desc, OrderPosition)as varchar)
                    from    TempTable where CustomerID = '+cast((select CustomerID from TempTable where id = @loop) as varchar)+
                    'order by orderID desc, OrderPosition'
    exec (@sql)
    select @loop = min(id) from TempTable where id > @loop
end

select
    CustomerID
,   sum(isnull([ArticleNumber 1],0))    [ArticleNumber 1]
,   sum(isnull([ArticleNumber 2],0))    [ArticleNumber 2]
,   sum(isnull([ArticleNumber 3],0))    [ArticleNumber 3]
,   sum(isnull([ArticleNumber 4],0))    [ArticleNumber 4]
from
(
select
CustomerID, OrderID, OrderPosition, ArticleDesc, ArticleNumber
from    TempTable2
group by CustomerID, OrderID, OrderPosition, ArticleDesc, ArticleNumber
)   d
pivot
(sum(ArticleNumber) for ArticleDesc in ([ArticleNumber 1],[ArticleNumber 2],[ArticleNumber 3],[ArticleNumber 4])
)   p
group by CustomerID

我的答案可能不是以上天才们回答的最好,但我仍然得到相同的结果...

Results

答案 1 :(得分:0)

修改后的示例数据可满足您的需求

IF OBJECT_ID('tempdb..#TEMP ')IS NOT NULL
DROP TABLE  #TEMP 
;WITH CTE(customerID , OrderID , OrderPosition , Articlenumber)
AS
(
SELECT 101,  1 , 1 , 123 UNION ALL         
SELECT 101,  1 , 2 , 799 UNION ALL         
SELECT 102,  2 , 1 , 111 UNION ALL         
SELECT 103,  3 , 1 , 456 UNION ALL         
SELECT 101,  4 , 1 , 789 UNION ALL         
SELECT 103,  5 , 1 , 444 UNION ALL         
SELECT 103,  5 , 2 , 999 UNION ALL         
SELECT 101,  6 , 1 , 555 UNION ALL         
SELECT 101,  6 , 2 , 777 UNION ALL         
SELECT 101,  6 , 3 , 222          
)
SELECT * , SUM(ArticleNumber)OVER(PARTITION BY customerID  ORDER BY customerID ) AS SumOfArticlePerCustomer
INTO #TEMP 
FROM
(
SELECT * ,
    ROW_NUMBER()OVER(PARTITION BY customerID ORDER BY OrderID DESC  ) RNk,
    'ArticleNumber_'+CAST(ROW_NUMBER()OVER(PARTITION BY customerID ORDER BY OrderID DESC ) AS VARCHAR(10))  AS ArticleNumberData
FROM CTE
)DT
WHERE RNk <= 4

SELECT * FROM #TEMP

动态Sql,用于动态生成列并达到预期结果

DECLARE @Sql nvarchar(max),
        @DynamicColumn nvarchar(max),
        @MaxDynamicColumn nvarchar(max)

SELECT @DynamicColumn = STUFF((SELECT DISTINCT', '+QUOTENAME(ArticleNumberData )
FROM #TEMP  FOR XML PATH ('')),1,1,'') 

SELECT @MaxDynamicColumn = STUFF((SELECT DISTINCT', '+'MAX('+QUOTENAME(ArticleNumberData )+') AS '+QUOTENAME(ArticleNumberData )+CHAR(13)+CHAR(10)
FROM #TEMP FOR XML PATH (''),TYPE).value('text()[1]','nvarchar(max)'),1,1,N'')

SET @Sql='SELECT  CustomerID,'+ @MaxDynamicColumn+',SumOfArticlePerCustomer 
            FROM
            (
            SELECT *
            FROM #TEMP 
            )AS src
            PIVOT 
            (
            MAX(Articlenumber) FOR [ArticleNumberData] IN ('+@DynamicColumn+')
            ) AS Pvt
            GROUP BY customerID,SumOfArticlePerCustomer
            ORDER BY  CustomerID'
EXEC (@Sql)
PRINT @Sql

答案 2 :(得分:0)

如果仅需四列,并且输出的结果与上面列出的相同,则始终可以使用ROW_NUMBER,CTE和一些联接:

;with TopFour
as
(
    SELECT *,
        ROW_NUMBER() OVER(PARTITION BY [customerID] ORDER BY orderID DESC, OrderPosition ASC) as [TheOrder]
    FROM [table]
)
SELECT
    a.[customerID],
    a.[Articlenumber] as [articlenumber 1],
    b.[Articlenumber] as [articlenumber 2],
    c.[Articlenumber] as [articlenumber 3],
    d.[Articlenumber] as [articlenumber 4]
FROM 
    TopFour a
LEFT JOIN 
    TopFour b
ON 
    a.customerID = b.customerID
AND 
    b.TheOrder = 2
LEFT JOIN
    TopFour c
ON 
    a.customerID = c.customerID
AND 
    c.TheOrder = 3
LEFT JOIN 
    TopFour d
ON 
    a.customerID = d.customerID
AND 
    d.TheOrder = 4
WHERE 
    a.TheOrder = 1