2017-11-11 63 views
0

我有以下表格。SQL複雜篩選器+數據透視表

用戶
userID  fullName 
5   Mr. Joe 
7   Mr. Bean 

用品
id  supplyDesc  isActive 
1  Ballpen   1 
2  Adhesive Tape 1 
3  White Paper  1 

SupplyRequests
id requestCode  forFrom  forTo  userID 
    1 SPR-2017-1  12-01-2017 02-28-2018 5 
    2 SPR-2017-2  12-01-2017 02-28-2018 7 
    3 SPR-2017-3  01-01-2018 03-31-2018 7 

SupplyRequestDetails
id rqID supplyID storeID qty isActive 
    1 1  1   1   1000 1 
    2 1  2   1   2000 1 
    3 1  1   12   2000 1 
    4 1  2   12   3000 1 
    5 1  1   13   3000 1 
    6 1  2   13   4000 1 
    7 2  1   10   100 1 
    8 2  2   10   200 1 
    9 2  1   11   200 1 
    10 2  2   11   300 1 
    11 3  1   10   1  1 
    12 3  2   10   2  1 
    13 3  1   11   2  1 
    14 3  2   11   3  1 

需求:

在給定日期範圍的情況下,獲取所有用戶的每個供應商的請求總數量以及他們請求的唯一分支的總數。必須是請求詳細信息和供應表中的活動供應項目。

注意 供應可能隨時改變

我試了一下,到目前爲止:

declare @forFrom varchar(50) = '12/01/2017' 
declare @forTo varchar(50) = '02/28/2018' 

declare @cols nvarchar(max), @cols2 nvarchar(max), @query NVARCHAR(MAX) 
select @cols = STUFF((SELECT DISTINCT ', MAX(' + QUOTENAME(supplyDesc) + ')' + '''' + supplyDesc + '''' 
         FROM (select a.id'supplyID', 
         a.supplyDesc, 
         SUBSTRING(d.fullName, 5, LEN(MAX(d.fullName)))fullName, 
         SUM(CASE WHEN ((CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo)) THEN b.qty ELSE 0 END)totalQty 
         from Supplies a 
         left join SupplyRequestDetails b 
         on a.id = b.supplyID 
         left join SupplyRequests c 
         on b.rqID = c.id 
         left join Users d 
         on c.userID = d.id 
         where a.isActive = 1 
         or b.isActive = 1 
         group by a.id, 
          a.supplyDesc, 
          fullName 
       ) as x 
       FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,''); 

select @cols2 = STUFF((SELECT DISTINCT ',' + QUOTENAME(supplyDesc) 
         FROM (select a.id'supplyID', 
         a.supplyDesc, 
         SUBSTRING(d.fullName, 5, LEN(MAX(d.fullName)))fullName, 
         SUM(CASE WHEN ((CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo)) THEN b.qty ELSE 0 END)totalQty 
         from Supplies a 
         left join SupplyRequestDetails b 
         on a.id = b.supplyID 
         left join SupplyRequests c 
         on b.rqID = c.id 
         left join Users d 
         on c.userID = d.id 
         where a.isActive = 1 
         or b.isActive = 1 
         group by a.id, 
          a.supplyDesc, 
          fullName 
       ) as x 
       FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

SET @query = N' 
declare @forFrom varchar(50) = ''12/01/2017'' 
declare @forTo varchar(50) = ''02/28/2018'' 
SELECT SUBSTRING(fullName, 5, LEN(fullName))fullName, ' + @cols + ' 
FROM (SELECT SUBSTRING(fullName, 5, LEN(fullName))fullName, ' + @cols + ' 
FROM (select a.id''supplyID'', 
       a.supplyDesc, 
       SUBSTRING(d.fullName, 5, LEN(MAX(d.fullName)))fullName, 
         SUM(CASE WHEN ((CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo)) THEN b.qty ELSE 0 END)totalQty 
       from Supplies a 
       left join SupplyRequestDetails b 
       on a.id = b.supplyID 
       left join SupplyRequests c 
       on b.rqID = c.id 
       left join Users d 
       on c.userID = d.id 
       where a.isActive = 1 
       or b.isActive = 1 
       group by a.id, 
        a.supplyDesc, 
        fullName 
) as j 
PIVOT (
    SUM(totalQty) FOR supplyDesc IN (' 
    + @cols2 
    + ') 

) AS a 
WHERE fullName is not null 
GROUP BY fullName 
ORDER BY fullName;'; 


PRINT @query 
EXEC sp_executesql @query 

結果是有點喜歡:

fullName  Ballpen  Adhesive Tape  White Paper 
Mr.Joe  6303   9505    NULL 

預期的結果集:

fullName uqStores Ballpen  Adhesive Tape  White Paper 
Mr. Joe 3   6000   4000    NULL 
Mr. Bean 2   300   500    NULL 

您可能會注意到,我首先嚐試從Supplies表中獲取項目列表,並嘗試(但失敗)將每個項目標記給在給定條件下分別請求每個項目的用戶(日期範圍和活動狀態)。然後,創建了動態欄目並準備了物資的一個樞紐。另外,我還沒有弄清楚如何從這些查詢中統計所有唯一的storeID。

我在想第一個問題是我如何試圖給每個項目添加用戶標籤。雖然,不知道如何讓他們同時一堆物品。

您的幫助將非常感謝。

編輯:

我不得不解決一些疑問。我相信我複製了錯誤的項目。

更新:

fullName  Ballpen  Adhesive Tape  White Paper 
Mr. Joe  6000   9000    NULL 
Mr. Bean  300   500    NULL 

PS:不知怎的,我到達的解決方案逐位。現在我只需要爲每個請求獲得獨特的商店。

更新:

這似乎是工作,但真的很亂。

DECLARE @forFrom varchar(50) = '12/01/2017' 
DECLARE @forTo varchar(50) = '02/28/2018' 

declare @cols nvarchar(max), @cols2 nvarchar(max), @query NVARCHAR(MAX) 
    select @cols = STUFF((SELECT DISTINCT ', MAX(' + QUOTENAME(supplyDesc) + ')' + '''' + supplyDesc + '''' 
          FROM (select DISTINCT a.id'supplyID', 
            a.supplyDesc, 
            COUNT(CASE WHEN ((CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo)) THEN b.storeID ELSE NULL END)numberOfStores, 
            SUBSTRING(d.fullName, 5, LEN(MAX(CASE WHEN (CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo) THEN d.fullName ELSE NULL END)))fullName, 
            SUM(CASE WHEN ((CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo)) THEN b.qty ELSE 0 END)totalQty 
           from Supplies a 
           left join SupplyRequestDetails b 
           on a.id = b.supplyID 
           left join SupplyRequests c 
           on b.rqID = c.id 
           left join Users d 
           on c.userID = d.id 
           where a.isActive = 1 
           or b.isActive = 1 
           group by a.id, 
            a.supplyDesc, 
            fullName 
        ) as x 
        FOR XML PATH(''), TYPE 
       ).value('.', 'NVARCHAR(MAX)') 
      ,1,1,''); 
    select @cols2 = STUFF((SELECT DISTINCT ',' + QUOTENAME(supplyDesc) 
          FROM (select DISTINCT a.id'supplyID', 
            a.supplyDesc, 
            COUNT(CASE WHEN ((CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo)) THEN b.storeID ELSE NULL END)numberOfStores, 
            SUBSTRING(d.fullName, 5, LEN(MAX(CASE WHEN (CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo) THEN d.fullName ELSE NULL END)))fullName, 
            SUM(CASE WHEN ((CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo)) THEN b.qty ELSE 0 END)totalQty 
           from Supplies a 
           left join SupplyRequestDetails b 
           on a.id = b.supplyID 
           left join SupplyRequests c 
           on b.rqID = c.id 
           left join Users d 
           on c.userID = d.id 
           where a.isActive = 1 
           or b.isActive = 1 
           group by a.id, 
            a.supplyDesc, 
            fullName 
        ) as x 
        FOR XML PATH(''), TYPE 
       ).value('.', 'NVARCHAR(MAX)') 
      ,1,1,'') 

    SET @query = N' 
    declare @forFrom varchar(50) = ''' + @forFrom + ''' 
    declare @forTo varchar(50) = ''' + @forTo + ''' 
    SELECT SUBSTRING(fullName, 5, LEN(fullName))fullName, COUNT(numberOfStores)numOfStores,' + @cols + ' 
    FROM (select DISTINCT a.id''supplyID'', 
       a.supplyDesc, 
       COUNT(CASE WHEN ((CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo)) THEN b.storeID ELSE NULL END)numberOfStores, 
       SUBSTRING(d.fullName, 5, LEN(MAX(CASE WHEN (CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo) THEN d.fullName ELSE NULL END)))fullName, 
       SUM(CASE WHEN ((CAST(c.forFrom as datetime) >= @forFrom and CAST(c.forTo as datetime) <= @forTo)) THEN b.qty ELSE 0 END)totalQty 
      from Supplies a 
      left join SupplyRequestDetails b 
      on a.id = b.supplyID 
      left join SupplyRequests c 
      on b.rqID = c.id 
      left join Users d 
      on c.userID = d.id 
      where a.isActive = 1 
      or b.isActive = 1 
      group by a.id, 
       a.supplyDesc, 
       fullName 
    ) as j 
    PIVOT (
     SUM(totalQty) FOR supplyDesc IN (' 
     + @cols2 
     + ') 

    ) AS a 
    WHERE fullName is not null 
    GROUP BY fullName 
    ORDER BY fullName;'; 

    EXEC sp_executesql @query 

當然有更好的方法來做到這一點。我真的很喜歡你的建議。

更新

派生和從@sarslan的答案編輯:

DECLARE @Query NVARCHAR(MAX) = ' 
SELECT * FROM (
    SELECT 
     S.supplyDesc 
     , fullName 
     , COUNT(DISTINCT storeID) [uqStores] 
     , SUM(qty) SumQty 
    FROM 
     Supplies S 
     LEFT JOIN (SELECT U.fullName, supplyID, storeID, qty, SRD.isActive FROM SupplyRequestDetails SRD 
         INNER JOIN SupplyRequests SR ON SRD.rqID = SR.id AND (SR.forFrom >= @forFrom AND SR.forTo <= @forTo) 
         INNER JOIN Users U ON SR.userID = U.userID) AS ST ON ST.supplyID = S.id 
    WHERE ST.isActive = 1 
    GROUP BY fullName, supplyDesc 
    HAVING COUNT(DISTINCT storeID) > 1 
) SRC 
PIVOT (SUM (SumQty) FOR supplyDesc IN (' + @ColNames + ')) PVT ' 

說,例如,在SupplyRequestDetails ID 1個項目要被失活。

結果是:

fullName  Ballpen  Adhesive Tape  White Paper 
Mr. Bean  5000   NULL    NULL 
Mr. Bean  NULL   9000    NULL 
Mr. Joe  300   500    NULL 

回答

1

你可以使用這個腳本。

declare @forFrom datetime = '12/01/2017' 
declare @forTo datetime = '02/28/2018' 

DECLARE @ColNames NVARCHAR(MAX)= '' 
SELECT @ColNames = @ColNames + ',' + QUOTENAME (supplyDesc) FROM Supplies WHERE isActive = 1 
SET @ColNames = STUFF(@ColNames,1,1,'') 

DECLARE @Query NVARCHAR(MAX) = ' 
SELECT * FROM (
    SELECT 
     S.supplyDesc 
     , fullName 
     , COUNT(DISTINCT storeID) [uqStores] 
     , SUM(qty) SumQty 
    FROM 
     Supplies S 
     LEFT JOIN (SELECT U.fullName, supplyID, storeID, qty, SRD.isActive FROM SupplyRequestDetails SRD 
         INNER JOIN SupplyRequests SR ON SRD.rqID = SR.id AND (SR.forFrom >= @forFrom AND SR.forTo <= @forTo) 
         INNER JOIN Users U ON SR.userID = U.userID 
        WHERE SRD.isActive = 1) AS ST ON ST.supplyID = S.id 
    WHERE S.isActive = 1 
    GROUP BY fullName, supplyDesc 
    HAVING COUNT(DISTINCT storeID) > 1 
) SRC 
PIVOT (SUM (SumQty) FOR supplyDesc IN (' + @ColNames + ')) PVT ' 


EXEC sp_executesql @Query, N'@forFrom DATETIME, @forTo DATETIME' , @forFrom = @forFrom, @forTo = @forTo 

結果:

fullName    uqStores Ballpen  Adhesive Tape White Paper 
-------------------- ----------- ----------- ------------- ----------- 
Mr. Bean    2   300   500   NULL 
Mr. Joe    3   6000  9000   NULL 
+0

整潔,但我不認爲supplyNames的靜態聲明會工作。耗材可能會不時變化。 – am0r

+0

另外,由於動態項目,我不得不即興創建動態數據透視表。 – am0r

+0

我改爲查詢動態供應商 –