2017-11-11 61 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

我改为查询动态供应商 –