SQL在没有聚合的情况下透视两个值(不是列)?

时间:2016-01-18 17:03:24

标签: sql-server tsql

我有一个查询,我需要获取名称& 销售中涉及的每个销售员的编号(ID)。

SELECT 
    S.SaleID,
    P.PersonID,
    P.Name
FROM Sale S
LEFT JOIN PersonSales PS ON PS.SaleID = S.SaleID
LEFT JOIN Person P ON P.PersonID = PS.PersonID

但我必须把它作为列显示:

SELECT * FROM (
SELECT 
    S.SaleID,
    P.PersonID,
    P.Name,
    // - This will give me numbers 1+ for each Sale, per Person
    DENSE_RANK() OVER (PARTITION BY S.SaleID OVER P.PersonID) AS [Person#]
FROM Sale S
LEFT JOIN PersonSales PS ON PS.SaleID = S.SaleID
LEFT JOIN Person P ON P.PersonID = PS.PersonID
) AS Q
PIVOT (
    AGGREGATE(?) FOR [Person#] IN ([1], [2], [3], [4], [5])
) AS P

我的问题是,如果NamePersonID不是聚合,而是枢轴中的这两个值,我该如何获得它?

像这样:

SaleID    Name      ID    Name      ID
1         Seller A  1     Seller B  2
2         Seller C  3
3         Seller A  1     Seller C  3

2 个答案:

答案 0 :(得分:1)

从我最近注意到的情况来看,case使用aggregates(min or max)的效果优于pivot,但不是很漂亮。

SELECT  SaleID,
        MAX(CASE WHEN [Person#] = 1 THEN NAME END) AS [Name],
        MAX(CASE WHEN [Person#] = 1 THEN PersonID END) AS [ID],
        MAX(CASE WHEN [Person#] = 2 THEN NAME END) AS [Name],
        MAX(CASE WHEN [Person#] = 2 THEN PersonID END) AS [ID],
        MAX(CASE WHEN [Person#] = 3 THEN NAME END) AS [Name],
        MAX(CASE WHEN [Person#] = 3 THEN PersonID END) AS [ID],
        MAX(CASE WHEN [Person#] = 4 THEN NAME END) AS [Name],
        MAX(CASE WHEN [Person#] = 4 THEN PersonID END) AS [ID],
        MAX(CASE WHEN [Person#] = 5 THEN NAME END) AS [Name],
        MAX(CASE WHEN [Person#] = 5 THEN PersonID END) AS [ID]
FROM    (SELECT S.SaleID,
                P.PersonID,
                P.Name,
                DENSE_RANK() OVER (PARTITION BY S.SaleID ORDER BY P.PersonID) AS [Person#]
         FROM   Sale S
                LEFT JOIN PersonSales PS ON PS.SaleID = S.SaleID
                LEFT JOIN Person P ON P.PersonID = PS.PersonID
        ) t
GROUP BY SaleID

使用更多聚合和更多旋转,您也可以使用。

SELECT  SaleId,
        MAX(Name1) [Name], MAX(Id1) [Id],
        MAX(Name2) [Name], MAX(Id2) [Id],
        MAX(Name3) [Name], MAX(Id3) [Id],
        MAX(Name4) [Name], MAX(Id4) [Id],
        MAX(Name5) [Name], MAX(Id5) [Id]
FROM    (SELECT S.SaleID,
                P.PersonID,
                P.Name,
                CONCAT('Name',DENSE_RANK() OVER (PARTITION BY S.SaleID ORDER BY P.PersonID)) AS [Person#],
                CONCAT('Id',DENSE_RANK() OVER (PARTITION BY S.SaleID ORDER BY P.PersonID)) AS [PersonID#]
         FROM   Sale S
                LEFT JOIN PersonSales PS ON PS.SaleID = S.SaleID
                LEFT JOIN Person P ON P.PersonID = PS.PersonID
        ) AS Q 
PIVOT ( MAX([Name]) FOR [Person#] IN ([Name1],[Name2],[Name3],[Name4],[Name5]) ) AS P1
PIVOT ( MAX([PersonID]) FOR [PersonID#] IN ([Id1],[Id2],[Id3],[Id4],[Id5]) ) AS P2
GROUP BY [SaleId]

答案 1 :(得分:0)

如果您可以连接ID和名称,这将是一种方式:

DECLARE @Person TABLE(ID INT, Name VARCHAR(100));
INSERT INTO @Person VALUES(1,'Seller A'),(2,'Seller B'),(3,'Seller C');

DECLARE @Sales TABLE(ID INT,PersonID INT);
INSERT INTO @Sales VALUES
 (1,1)
,(1,2)
,(2,3)
,(3,1)
,(3,3);

SELECT pvt.*
FROM
(
    SELECT ROW_NUMBER() OVER(PARTITION BY S.ID ORDER BY P.ID) AS Inx
          ,S.ID AS SaleID
          ,P.Name + ' (' + CAST(P.ID AS VARCHAR(10)) + ')' AS Name
    FROM @Sales AS S
    INNER JOIN @Person AS P ON S.PersonID=P.ID
) AS tbl
PIVOT
(
    MIN(Name) FOR Inx IN([1],[2],[3])   
) AS pvt

如果您想要连接ID和名称,这是一个诀窍:诀窍是连接它,但让它看起来像XML 。这之后您可以轻松拆分(typesafe!)。

SELECT pvt.SaleID
      ,CAST(pvt.[1] AS XML).value('/x[1]','varchar(max)') AS Person_1
      ,CAST(pvt.[1] AS XML).value('/x[2]','int') AS PersonID_1  
      ,CAST(pvt.[2] AS XML).value('/x[1]','varchar(max)') AS Person_2
      ,CAST(pvt.[2] AS XML).value('/x[2]','int') AS PersonID_2
      ,CAST(pvt.[3] AS XML).value('/x[1]','varchar(max)') AS Person_3
      ,CAST(pvt.[3] AS XML).value('/x[2]','int') AS PersonID_3  
FROM
(
    SELECT ROW_NUMBER() OVER(PARTITION BY S.ID ORDER BY P.ID) AS Inx
          ,S.ID AS SaleID
          ,'<x>' + P.Name  + '</x><x>' + CAST(P.ID AS VARCHAR(10)) + '</x>' AS NameAsXml
    FROM @Sales AS S
    INNER JOIN @Person AS P ON S.PersonID=P.ID
) AS tbl
PIVOT
(
    MIN(NameAsXml) FOR Inx IN([1],[2],[3])  
) AS pvt