SQL复杂筛选器+数据透视表
问题描述:
我有以下表格。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
答
你可以使用这个脚本。
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
整洁,但我不认为supplyNames的静态声明会工作。耗材可能会不时变化。 – am0r
另外,由于动态项目,我不得不即兴创建动态数据透视表。 – am0r
我改为查询动态供应商 –