Dynamic Pivot中的总和错误值

时间:2015-09-05 11:52:36

标签: sql sql-server sum pivot distinct

我的查询很复杂,效果很好(MS SQL 2012)。但总结同样的价格项时却犯了一个错误。它正确计算它们但只收取一次价格而不是将它们作为计数。仅当相同的商品具有相同的价格且来自同一国家时才会出现。这是我的询问;

CREATE TABLE #ITEMS(ID INT,NAME VARCHAR(30))

INSERT INTO #ITEMS
SELECT 1,     'laptop'
UNION ALL
SELECT 2,     'phone'
UNION ALL
SELECT 3,     'playstation'
UNION ALL
SELECT 4,     'MacBook'

CREATE TABLE #Country(ID INT,NAME VARCHAR(30))

INSERT INTO #Country
SELECT 1,     'England'
UNION ALL
SELECT 2,     'Sweden'
UNION ALL
SELECT 3,     'Russia'
UNION ALL
SELECT 4,     'Italy'


CREATE TABLE [#Pre-Request](Id INT,  countryId INT,  ItemId INT) 

INSERT INTO [#Pre-Request]
SELECT 1,1,3
UNION ALL
SELECT 2,2,1
UNION ALL
SELECT 3,2,2
UNION ALL
SELECT 4,3,3
UNION ALL
SELECT 5,3,3
UNION ALL
SELECT 6,2,3

CREATE TABLE #Offers(Id INT,  PRICE VARCHAR(50))

INSERT INTO #Offers
SELECT 18,'257$'
UNION ALL
SELECT 19,'151$'
UNION ALL
SELECT 20,'424$'   
UNION ALL
SELECT 21,'433$'
UNION ALL
SELECT 22,'151$' 

CREATE TABLE #Request(Id INT,  preReqId INT,  requestStatus INT,winOfferId INT) 

INSERT INTO #Request
SELECT 44,        1,          3,                   18
UNION ALL
SELECT 11,        2,          4,                   21
UNION ALL
SELECT 53,        3,          4,                   20
UNION ALL
SELECT 87,        4,          3,                   22
UNION ALL
SELECT 43,        5,          3,                   19
UNION ALL
SELECT 43,        6,          2,                   Null




;WITH CTE AS
(
    SELECT DISTINCT I.NAME ITEMNAME,C.NAME COUNTRYNAME
    ,CAST(REPLACE(TAB.PRICE,'$','')AS INT)PRICE
    ,COUNT(CASE WHEN TAB.PRICE IS NOT NULL THEN I.NAME END) OVER(PARTITION BY C.NAME,I.NAME) CNTITEM    
    FROM [#Pre-Request] PR
    LEFT JOIN #Items I ON PR.ITEMID=I.ID
    LEFT JOIN #COUNTRY C ON PR.COUNTRYID = C.ID
    OUTER APPLY
    (
        SELECT R.preReqId,R.winOfferId,O.PRICE
        FROM #Request R 
        JOIN #Offers O ON R.winOfferId=O.Id
        WHERE PR.ID=R.preReqId
    )TAB

    UNION 
    -- Used to select Item name and country that are not in Pre-request table and other tables
    SELECT I.NAME ,C.NAME ,NULL,0
    FROM #Items I
    CROSS JOIN #COUNTRY C
)
,CTE2 AS
(
    -- Find the sum for number of items
    SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME,
    SUM(PRICE)PRICE 
    FROM CTE
    GROUP BY ITEMNAME,COUNTRYNAME
    WITH CUBE
)
,CTE3 AS
(
    -- Find the sum of PRICE
    SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME--,CNTITEM
    ,SUM(CNTITEM)CNTITEM    
    FROM 
    (
        SELECT DISTINCT ITEMNAME,COUNTRYNAME,CNTITEM
        FROM CTE
    )TAB
    GROUP BY ITEMNAME,COUNTRYNAME
    WITH CUBE
)
SELECT C2.*,C3.CNTITEM,
CAST(C3.CNTITEM AS VARCHAR(20))+'x'+' ' + CAST(C2.PRICE AS VARCHAR(20))+'$' NEWCOL
INTO #NEWTABLE
FROM CTE2 C2
JOIN CTE3 C3 ON C2.COUNTRYNAME=C3.COUNTRYNAME AND C2.ITEMNAME=C3.ITEMNAME







DECLARE @cols NVARCHAR (MAX)

SELECT @cols = COALESCE (@cols + ',[' + ITEMNAME + ']', '[' + ITEMNAME + ']')
               FROM (SELECT DISTINCT ITEMNAME FROM #NEWTABLE WHERE ITEMNAME<>'TOTAL') PV 
               ORDER BY ITEMNAME 
-- Since we need Total in last column, we append it at last
SELECT @cols += ',[Total]'


DECLARE @query NVARCHAR(MAX)
SET @query = 'SELECT COUNTRYNAME,' + @cols + ' FROM 
             (
                 SELECT DISTINCT ITEMNAME,COUNTRYNAME,ISNULL(NEWCOL,''0x 0$'')NEWCOL
                 FROM #NEWTABLE
             ) x
             PIVOT 
             (
                 MIN(NEWCOL)
                 FOR ITEMNAME IN (' + @cols + ')
            ) p
            ORDER BY CASE WHEN (COUNTRYNAME=''Total'') THEN 1 ELSE 0 END,COUNTRYNAME' 

EXEC SP_EXECUTESQL @query

这是结果;

enter image description here

正如你所看到的,有2&#34; playstation&#34;来自&#34;俄罗斯&#34;它需要正确的计数(2x),但只需要1个价格&#34; 151 $&#34; (通常必须是302美元)。如何在不对查询进行重大更改的情况下解决此问题?谢谢。

1 个答案:

答案 0 :(得分:2)

我认为这可以满足您的需求。问题在于您的第一个CTE,您在其中执行项目计数并获得ItemName,CountryName和Price的不同。

不是获得明确的,而是通过如下所示进行分组并使价格合并。

    SELECT I.NAME ITEMNAME, C.NAME COUNTRYNAME
,SUM(CAST(REPLACE(TAB.PRICE,'$','')AS INT))PRICE
,COUNT(CASE WHEN TAB.PRICE IS NOT NULL THEN 1 ELSE NULL END) CNTITEM    
FROM [#Pre-Request] PR
LEFT JOIN #Items I ON PR.ITEMID=I.ID
LEFT JOIN #COUNTRY C ON PR.COUNTRYID = C.ID
OUTER APPLY
(
    SELECT R.preReqId,R.winOfferId,O.PRICE
    FROM #Request R 
    JOIN #Offers O ON R.winOfferId=O.Id
    WHERE PR.ID=R.preReqId
)TAB
GROUP BY
    I.NAME 
    ,C.NAME

编辑: 以下是我得到的结果:

enter image description here

以下是从CTE开始的所有代码:

;WITH CTE AS
(
    SELECT I.NAME ITEMNAME, C.NAME COUNTRYNAME
    ,SUM(CAST(REPLACE(TAB.PRICE,'$','')AS INT))PRICE
    ,COUNT(CASE WHEN TAB.PRICE IS NOT NULL THEN 1 ELSE NULL END) CNTITEM    
    FROM [#Pre-Request] PR
    LEFT JOIN #Items I ON PR.ITEMID=I.ID
    LEFT JOIN #COUNTRY C ON PR.COUNTRYID = C.ID
    OUTER APPLY
    (
        SELECT R.preReqId,R.winOfferId,O.PRICE
        FROM #Request R 
        JOIN #Offers O ON R.winOfferId=O.Id
        WHERE PR.ID=R.preReqId
    )TAB
    GROUP BY
        I.NAME 
        ,C.NAME

    UNION 
    -- Used to select Item name and country that are not in Pre-request table and other tables
    SELECT I.NAME ,C.NAME ,NULL,0
    FROM #Items I
    CROSS JOIN #COUNTRY C
)
,CTE2 AS
(
    -- Find the sum for number of items
    SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME,
    SUM(PRICE)PRICE 
    FROM CTE
    GROUP BY ITEMNAME,COUNTRYNAME
    WITH CUBE
)
,CTE3 AS
(
    -- Find the sum of PRICE
    SELECT DISTINCT ISNULL(ITEMNAME,'TOTAL')ITEMNAME,ISNULL(COUNTRYNAME,'TOTAL')COUNTRYNAME--,CNTITEM
    ,SUM(CNTITEM)CNTITEM    
    FROM 
    (
        SELECT DISTINCT ITEMNAME,COUNTRYNAME,CNTITEM
        FROM CTE
    )TAB
    GROUP BY ITEMNAME,COUNTRYNAME
    WITH CUBE
)

SELECT C2.*,C3.CNTITEM,
CAST(C3.CNTITEM AS VARCHAR(20))+'x'+' ' + CAST(C2.PRICE AS VARCHAR(20))+'$' NEWCOL
INTO #NEWTABLE
FROM CTE2 C2
JOIN CTE3 C3 ON C2.COUNTRYNAME=C3.COUNTRYNAME AND C2.ITEMNAME=C3.ITEMNAME







DECLARE @cols NVARCHAR (MAX)

SELECT @cols = COALESCE (@cols + ',[' + ITEMNAME + ']', '[' + ITEMNAME + ']')
               FROM (SELECT DISTINCT ITEMNAME FROM #NEWTABLE WHERE ITEMNAME<>'TOTAL') PV 
               ORDER BY ITEMNAME 
-- Since we need Total in last column, we append it at last
SELECT @cols += ',[Total]'


DECLARE @query NVARCHAR(MAX)
SET @query = 'SELECT COUNTRYNAME,' + @cols + ' FROM 
             (
                 SELECT DISTINCT ITEMNAME,COUNTRYNAME,ISNULL(NEWCOL,''0x 0$'')NEWCOL
                 FROM #NEWTABLE
             ) x
             PIVOT 
             (
                 MIN(NEWCOL)
                 FOR ITEMNAME IN (' + @cols + ')
            ) p
            ORDER BY CASE WHEN (COUNTRYNAME=''Total'') THEN 1 ELSE 0 END,COUNTRYNAME' 

EXEC SP_EXECUTESQL @query