[英]T-SQL How to “Flatten” top 3 rows into a single row
I've searched for an answer to this question and found questions similar to my own, however I do not have a "ColumnHeader" column to denote which field the record should go into. 我已经搜索了该问题的答案,发现了与我自己的问题类似的问题,但是我没有“ ColumnHeader”列来表示记录应进入哪个字段。 Ex:
例如:
TSQL Pivot without aggregate function 没有聚合功能的TSQL Pivot
trying to flatten rows into columns 试图将行平整为列
Fetching Columns of a multiple rows in one row 在一行中获取多行的列
My problem is thus - I have data in this format (selected as a top 3 result from a product recommendation query): 因此,我的问题是-我有这种格式的数据(从产品推荐查询中选择为前3个结果):
------------------------------
CustID | StyleNo | Brand | ID
------------------------------
1 | ABC | BrandA| 1
------------------------------
1 | DEF | BrandB| 2
------------------------------
1 | GHI | BrandC| 3
------------------------------
2 | JKL | BrandA| 4
------------------------------
2 | MNO | BrandB| 5
------------------------------
2 | PQR | BrandD| 6
------------------------------
That I'd like to make look like this: 我想要看起来像这样:
-----------------------------------------------------------------
CustID | StyleNo1| StyleNo2| StyleNo3 | Brand1 | Brand2 | Brand3
-----------------------------------------------------------------
1 | ABC | DEF | GHI | BrandA | BrandB | BrandC
-----------------------------------------------------------------
2 | JKL | MNO | PQR | BrandA | BrandB | BrandD
-----------------------------------------------------------------
In order for my program to simply read the row of recommendations for each customer. 为了使我的程序能够轻松阅读针对每个客户的建议行。
What I have attempted is a PIVOT
- however I have nothing to really aggregate upon. 我尝试过的是
PIVOT
但是我没有什么可总结的。 I've also attempted the Min(Case...When...Then...End)
as outlined in the second linked question, but as stated I don't have reference to a "Header" column. 我还尝试了第二个链接问题中概述的
Min(Case...When...Then...End)
,但是如上所述,我没有引用“ Header”列。
The ID column is completely inconsequential for the time being, but it may help to solve this problem. ID列暂时是完全无关紧要的,但它可能有助于解决此问题。 It is NOT needed in the end result.
最终结果不需要它。
I am currently using SQLServer 2012 我目前正在使用SQLServer 2012
With the window function Row_Number() and a conditional aggregation 使用窗口函数Row_Number()和条件聚合
Select CustID
,StyleNo1 = max(case when RN=1 then StyleNo else null end)
,StyleNo2 = max(case when RN=2 then StyleNo else null end)
,StyleNo3 = max(case when RN=3 then StyleNo else null end)
,Brand1 = max(case when RN=1 then Brand else null end)
,Brand2 = max(case when RN=2 then Brand else null end)
,Brand3 = max(case when RN=3 then Brand else null end)
From (
Select *,RN = Row_Number() over (Partition By CustID Order by StyleNo,Brand)
From YourTable
) A
Where RN<=3
Group By CustID
Returns 返回
What you are doing is called "pivoting" - for this you could use PIVOT . 您正在做的事情称为“透视”-为此,您可以使用PIVOT 。 A better way IMHO is to use approach that Jeff Moden talks about in this article .
恕我直言,更好的方法是使用Jeff Moden在本文中谈到的方法。
WITH idSort AS
(
SELECT *, rn = ROW_NUMBER() OVER (PARTITION BY CustID ORDER BY ID) FROM @yourTable
)
SELECT
CustID,
StyleNo1 = MAX(CASE rn WHEN 1 THEN StyleNo END),
StyleNo2 = MAX(CASE rn WHEN 2 THEN StyleNo END),
StyleNo3 = MAX(CASE rn WHEN 3 THEN StyleNo END),
Brand1 = MAX(CASE rn WHEN 1 THEN Brand END),
Brand2 = MAX(CASE rn WHEN 2 THEN Brand END),
Brand3 = MAX(CASE rn WHEN 3 THEN Brand END)
FROM idSort
GROUP BY CustID;
Other approach can be using CTE's and Cross Apply. 其他方法可以使用CTE和Cross Apply。
CREATE TABLE #UnFlattenedData
(
CustID TINYINT ,
StyleNo CHAR(3) ,
Brand CHAR(6) ,
ID TINYINT
);
INSERT INTO #UnFlattenedData
( CustID, StyleNo, Brand, ID )
VALUES ( 1, -- CustID - tinyint
'ABC', -- StyleNo - char(3)
'BrandA', -- Brand - char(6)
1 -- ID - tinyint
),
( 1, -- CustID - tinyint
'DEF', -- StyleNo - char(3)
'BrandB', -- Brand - char(6)
2 -- ID - tinyint
),
( 1, -- CustID - tinyint
'GHI', -- StyleNo - char(3)
'BrandC', -- Brand - char(6)
3 -- ID - tinyint
),
( 2, -- CustID - tinyint
'JKL', -- StyleNo - char(3)
'BrandA', -- Brand - char(6)
4 -- ID - tinyint
),
( 2, -- CustID - tinyint
'MNO', -- StyleNo - char(3)
'BrandB', -- Brand - char(6)
5 -- ID - tinyint
),
( 2, -- CustID - tinyint
'PQR', -- StyleNo - char(3)
'BrandD', -- Brand - char(6)
6 -- ID - tinyint
);
WITH cte
AS ( SELECT * ,
ROW_NUMBER() OVER ( PARTITION BY u1.CustID ORDER BY u1.ID ) AS R1
FROM #UnFlattenedData AS u1
),
u1
AS ( SELECT C1.CustID ,
U1.StyleNo ,
U1.Brand
FROM cte AS C1
INNER JOIN #UnFlattenedData AS U1 ON U1.CustID = C1.CustID
AND U1.ID = C1.ID
WHERE C1.R1 = 1
),
u2
AS ( SELECT C1.CustID ,
U1.StyleNo ,
U1.Brand
FROM cte AS C1
INNER JOIN #UnFlattenedData AS U1 ON U1.CustID = C1.CustID
AND U1.ID = C1.ID
WHERE C1.R1 = 2
),
u3
AS ( SELECT C1.CustID ,
U1.StyleNo ,
U1.Brand
FROM cte AS C1
INNER JOIN #UnFlattenedData AS U1 ON U1.CustID = C1.CustID
AND U1.ID = C1.ID
WHERE C1.R1 = 3
)
SELECT u1.CustID ,
u1.StyleNo AS StyleNo1 ,
u2.StyleNo AS StyleNo2 ,
u3.StyleNo AS StyleNo3 ,
u1.Brand AS Brand1 ,
u2.Brand AS Brand2 ,
u3.Brand AS Brand3
FROM u1
CROSS APPLY ( SELECT *
FROM u2
WHERE u2.CustID = u1.CustID
) AS u2
CROSS APPLY ( SELECT *
FROM u3
WHERE u3.CustID = u1.CustID
) AS u3;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.