简体   繁体   English

T-SQL如何将前3行“平整”成单行

[英]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.

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