Sql 按两个不同的分组求和
我从报告中得到了错误的结果。也许我错过了一些简单的事情 该报告是一个内联表值函数,它应该统计我们商店中的货物移动以及这些备件的索赔频率(在维修中更换) 问题:shop表中的不同sparepart(我们称之为Sql 按两个不同的分组求和,sql,sql-server,sql-server-2005,tsql,Sql,Sql Server,Sql Server 2005,Tsql,我从报告中得到了错误的结果。也许我错过了一些简单的事情 该报告是一个内联表值函数,它应该统计我们商店中的货物移动以及这些备件的索赔频率(在维修中更换) 问题:shop表中的不同sparepart(我们称之为SP)可以链接到“repair table”(TSP)中的同一sparepart。我需要SP中每个备件的货物移动和TSP中每个distinct备件的索赔计数 这是相关部分的一个非常简化的摘录: create table #tsp(id int, name varchar(20),claimed
SP
)可以链接到“repair table”(TSP)中的同一sparepart。我需要SP
中每个备件的货物移动和TSP
中每个distinct备件的索赔计数
这是相关部分的一个非常简化的摘录:
create table #tsp(id int, name varchar(20),claimed int);
create table #sp(id int, name varchar(20),fiTsp int,ordered int);
insert into #tsp values(1,'1235-6044',300);
insert into #tsp values(2,'1234-5678',400);
insert into #sp values(1,'1235-6044',1,30);
insert into #sp values(2,'1235-6044',1,40);
insert into #sp values(3,'1235-6044',1,50);
insert into #sp values(4,'1234-5678',2,60);
WITH cte AS(
select tsp.id As TspID,tsp.name as TspName,tsp.claimed As Claimed
,sp.id As SpID,sp.name As SpName,sp.ordered As Ordered
from #sp sp inner join #tsp tsp
on sp.fiTsp=tsp.id
)
SELECT TspName, SUM(Claimed) As Claimed, Sum(Ordered) As Ordered
FROM cte
Group By TspName
drop table #tsp;
drop table #sp;
结果:
TspName Claimed Ordered
1234-5678 400 60
1235-6044 900 120
订购的计数正确,但对于TspName='1235-6044',声称的计数应为300而不是900
我需要根据Tsp.ID
对索赔计数进行分组,并根据Sp.ID
对订单计数进行分组。但如何在一个问题
编辑:实际上TVF看起来像(请注意,getOrdered
和getClaimed
是SVF,我在TSP的外部选择类别中分组):
解决方案:
多亏了Aliostad,我通过先分组然后加入(实际TVF,减少到最小值)解决了这个问题:
您先加入,然后按分组。您需要将其反转,先分组,然后加入
在我的子查询中,我先分组,然后加入:
select
claimed,
ordered
from
#tsp
inner JOIN
(select
fitsp,
SUM(ordered) as ordered
from
#sp
group by
fitsp) as SUMS
on
SUMS.fiTsp = id;
您的cte
是tsp
和sp
之间的内部连接,这意味着您要查询的数据如下所示:
SpID Ordered TspID TspName Claimed
1 30 1 1235-6044 300
2 40 1 1235-6044 300
3 50 1 1235-6044 300
4 60 2 1234-5678 400
注意TspID
,TspName
和声明的
都是如何重复的。按TspName
分组意味着将数据分为两组,一组用于1235-6044
,另一组用于1234-5678
。第一个组有3行运行聚合函数,第二个组只有一行。这就是为什么你的金额(索赔)
会得到300*3=900
正如Aliostad所建议的,您应该首先按TspID
分组,然后对排序的进行求和,然后加入tsp
,我认为您只需要选择Claimed并将其添加到group by中,即可获得您想要的内容
WITH cte AS(
select tsp.id As TspID,tsp.name as TspName,tsp.claimed As Claimed
,sp.id As SpID,sp.name As SpName,sp.ordered As Ordered
from #sp sp inner join #tsp tsp
on sp.fiTsp=tsp.id )
SELECT TspName, Claimed, Sum(Ordered) As Ordered
FROM cte
Group By TspName, Claimed
无需加入,只需再次选择:
create table #tsp(id int, name varchar(20),claimed int);
create table #sp(id int, name varchar(20),fiTsp int,ordered int);
insert into #tsp values(1,'1235-6044',300);
insert into #tsp values(2,'1234-5678',400);
insert into #sp values(1,'1235-6044',1,30);
insert into #sp values(2,'1235-6044',1,40);
insert into #sp values(3,'1235-6044',1,50);
insert into #sp values(4,'1234-5678',2,60);
WITH cte AS(
select tsp.id As TspID,tsp.name as TspName,tsp.claimed As Claimed
,sp.id As SpID,sp.name As SpName,sp.ordered As Ordered
from #sp sp inner join #tsp tsp
on sp.fiTsp=tsp.id
)
SELECT id, name, SUM(claimed) as Claimed, (SELECT SUM(ordered) FROM #sp WHERE #sp.fiTsp = #tsp.id GROUP BY #sp.fiTsp) AS Ordered
FROM #tsp
GROUP BY id, name
drop table #tsp;
drop table #sp;
CREATE FUNCTION [Gambio].[rptReusedStatistics](
@fromDate datetime
,@toDate datetime
,@fromInvoiceDate datetime
,@toInvoiceDate datetime
,@idClaimStatus varchar(50)
,@idSparePartCategories varchar(1000)
,@idSpareParts varchar(1000)
)
RETURNS TABLE AS
RETURN(
WITH ExclusionCat AS (
SELECT idSparePartCategory AS ID From tabSparePartCategory
WHERE idSparePartCategory IN(- 3, - 1, 6, 172,168)
), ReportSP AS (
SELECT fiTabSparePart
,Inventory
,Gambio.getGoodsIn(idSparePart,@FromDate,@ToDate) GoodsIn
,Gambio.getOrdered(idSparePart,@FromDate,@ToDate) Ordered
FROM Gambio.SparePart
), ReportTSP AS (
SELECT TSP.idSparePart
,Cat.SparePartCategoryName AS Category
,TSP.SparePartDescription AS Part
,TSP.SparePartName AS PartNumber
,CASE WHEN TSP.idSparePart IS NULL THEN 0 ELSE
Gambio.getClaimed(TSP.idSparePart,@FromInvoiceDate,@ToInvoiceDate,@idClaimStatus,1)END AS ClaimedReused
,CASE WHEN TSP.idSparePart IS NULL THEN 0 ELSE
Gambio.getCostSaving(TSP.idSparePart,@FromInvoiceDate,@ToInvoiceDate,@idClaimStatus)END AS Costsaving
FROM tabSparePart AS TSP
INNER JOIN tabSparePartCategory AS Cat
ON Cat.idSparePartCategory=TSP.fiSparePartCategory
WHERE Cat.idSparePartCategory NOT IN(SELECT ID FROM ExclusionCat)
AND (@idSparePartCategories IS NULL
OR TSP.fiSparePartCategory IN(
SELECT Item From dbo.Split(@idSparePartCategories,',')
)
)
AND (@idSpareParts IS NULL
OR TSP.idSparePart IN(
SELECT Item From dbo.Split(@idSpareParts,',')
)
)
)
SELECT Category
--, Part
--, PartNumber
, (SELECT SUM(Inventory) FROM ReportSP WHERE ReportSP.fiTabSparePart = idSparePart GROUP BY fiTabSparePart) AS Inventory
, (SELECT SUM(GoodsIn) FROM ReportSP WHERE ReportSP.fiTabSparePart = idSparePart GROUP BY fiTabSparePart) AS GoodsIn
, (SELECT SUM(Ordered) FROM ReportSP WHERE ReportSP.fiTabSparePart = idSparePart GROUP BY fiTabSparePart) AS Ordered
, Claimed
, ClaimedReused
, Costsaving
, Count(*) AS PartCount
FROM ReportTSP
GROUP BY Category
)
产生:
id name Claimed Ordered
1 1235-6044 300 120
2 1234-5678 400 60
--编辑--
根据附加信息,我可能会尝试按照示例分割CTE以形成数据。我完全承认Aliostad的方法可能会产生更清晰的查询,但这里有一个尝试(完全盲目)使用subselect:
create table #tsp(id int, name varchar(20),claimed int);
create table #sp(id int, name varchar(20),fiTsp int,ordered int);
insert into #tsp values(1,'1235-6044',300);
insert into #tsp values(2,'1234-5678',400);
insert into #sp values(1,'1235-6044',1,30);
insert into #sp values(2,'1235-6044',1,40);
insert into #sp values(3,'1235-6044',1,50);
insert into #sp values(4,'1234-5678',2,60);
WITH cte AS(
select tsp.id As TspID,tsp.name as TspName,tsp.claimed As Claimed
,sp.id As SpID,sp.name As SpName,sp.ordered As Ordered
from #sp sp inner join #tsp tsp
on sp.fiTsp=tsp.id
)
SELECT id, name, SUM(claimed) as Claimed, (SELECT SUM(ordered) FROM #sp WHERE #sp.fiTsp = #tsp.id GROUP BY #sp.fiTsp) AS Ordered
FROM #tsp
GROUP BY id, name
drop table #tsp;
drop table #sp;
CREATE FUNCTION [Gambio].[rptReusedStatistics](
@fromDate datetime
,@toDate datetime
,@fromInvoiceDate datetime
,@toInvoiceDate datetime
,@idClaimStatus varchar(50)
,@idSparePartCategories varchar(1000)
,@idSpareParts varchar(1000)
)
RETURNS TABLE AS
RETURN(
WITH ExclusionCat AS (
SELECT idSparePartCategory AS ID From tabSparePartCategory
WHERE idSparePartCategory IN(- 3, - 1, 6, 172,168)
), ReportSP AS (
SELECT fiTabSparePart
,Inventory
,Gambio.getGoodsIn(idSparePart,@FromDate,@ToDate) GoodsIn
,Gambio.getOrdered(idSparePart,@FromDate,@ToDate) Ordered
FROM Gambio.SparePart
), ReportTSP AS (
SELECT TSP.idSparePart
,Cat.SparePartCategoryName AS Category
,TSP.SparePartDescription AS Part
,TSP.SparePartName AS PartNumber
,CASE WHEN TSP.idSparePart IS NULL THEN 0 ELSE
Gambio.getClaimed(TSP.idSparePart,@FromInvoiceDate,@ToInvoiceDate,@idClaimStatus,1)END AS ClaimedReused
,CASE WHEN TSP.idSparePart IS NULL THEN 0 ELSE
Gambio.getCostSaving(TSP.idSparePart,@FromInvoiceDate,@ToInvoiceDate,@idClaimStatus)END AS Costsaving
FROM tabSparePart AS TSP
INNER JOIN tabSparePartCategory AS Cat
ON Cat.idSparePartCategory=TSP.fiSparePartCategory
WHERE Cat.idSparePartCategory NOT IN(SELECT ID FROM ExclusionCat)
AND (@idSparePartCategories IS NULL
OR TSP.fiSparePartCategory IN(
SELECT Item From dbo.Split(@idSparePartCategories,',')
)
)
AND (@idSpareParts IS NULL
OR TSP.idSparePart IN(
SELECT Item From dbo.Split(@idSpareParts,',')
)
)
)
SELECT Category
--, Part
--, PartNumber
, (SELECT SUM(Inventory) FROM ReportSP WHERE ReportSP.fiTabSparePart = idSparePart GROUP BY fiTabSparePart) AS Inventory
, (SELECT SUM(GoodsIn) FROM ReportSP WHERE ReportSP.fiTabSparePart = idSparePart GROUP BY fiTabSparePart) AS GoodsIn
, (SELECT SUM(Ordered) FROM ReportSP WHERE ReportSP.fiTabSparePart = idSparePart GROUP BY fiTabSparePart) AS Ordered
, Claimed
, ClaimedReused
, Costsaving
, Count(*) AS PartCount
FROM ReportTSP
GROUP BY Category
)
如果不更好地理解整个模式,就很难涵盖所有可能发生的情况,但这是否有效(我怀疑所有实例的PartCount都是1)希望它能为您提供一些新的思路来选择其他方法。MAX
对我没有帮助,因为它只对这个小样本数据有效,而不适用于我在SparePartCategories(TSP属于一个类别)上分组的整个查询。我需要索赔单上的金额通常也是正确的。谢谢。我在问题中没有提到它,但实际上我通过标量值函数得到了顺序计数和索赔计数。第一个将SP.ID作为参数,第二个将TSP.ID作为参数。因此,我需要一个CTE,它将所有SP传递给getOrdered
,将所有不同的TSP传递给getClaimed
。所以我不能在这个CTE中进行子选择,因为它不是计算它的位置(实际上它并没有那么简单)。SUM
将应用于使用CTE和类别分组的外部选择(每个TSP属于一个类别)。@TimSchmelter标量函数是一成不变的吗?根据我对结构的理解,SP.id是不相关的,您应该能够将TSP.id传递给两者。恐怕它们都是,实际上计算要困难得多。订单计数和索赔计数都不是这些表中的列,但必须根据其他事实表中给定的时间跨度、状态和重用标志进行计算。因此我创建了这些标量函数。所以我试着用这个简化的例子来概括这个问题。我能想到的最简单的选择就是按照这个例子,创建两个表。将您的报告
查询分为两个查询,生成一个SP记录表和一个TSP订单表,然后最后一个阶段可以按照I或Aliostad指示进行分组。感谢您提供两个查询的示例。但最后,我成功地将Aliostad的方法应用到我的TVF中(请参见我的编辑),它工作完美,速度足够快。谢谢。在我把你的建议带到我的TVF(看看我的编辑)后,它工作得非常好。很高兴听到它都被修复了。
CREATE FUNCTION [Gambio].[rptReusedStatistics](
@fromDate datetime
,@toDate datetime
,@fromInvoiceDate datetime
,@toInvoiceDate datetime
,@idClaimStatus varchar(50)
,@idSparePartCategories varchar(1000)
,@idSpareParts varchar(1000)
)
RETURNS TABLE AS
RETURN(
WITH ExclusionCat AS (
SELECT idSparePartCategory AS ID From tabSparePartCategory
WHERE idSparePartCategory IN(- 3, - 1, 6, 172,168)
), ReportSP AS (
SELECT fiTabSparePart
,Inventory
,Gambio.getGoodsIn(idSparePart,@FromDate,@ToDate) GoodsIn
,Gambio.getOrdered(idSparePart,@FromDate,@ToDate) Ordered
FROM Gambio.SparePart
), ReportTSP AS (
SELECT TSP.idSparePart
,Cat.SparePartCategoryName AS Category
,TSP.SparePartDescription AS Part
,TSP.SparePartName AS PartNumber
,CASE WHEN TSP.idSparePart IS NULL THEN 0 ELSE
Gambio.getClaimed(TSP.idSparePart,@FromInvoiceDate,@ToInvoiceDate,@idClaimStatus,1)END AS ClaimedReused
,CASE WHEN TSP.idSparePart IS NULL THEN 0 ELSE
Gambio.getCostSaving(TSP.idSparePart,@FromInvoiceDate,@ToInvoiceDate,@idClaimStatus)END AS Costsaving
FROM tabSparePart AS TSP
INNER JOIN tabSparePartCategory AS Cat
ON Cat.idSparePartCategory=TSP.fiSparePartCategory
WHERE Cat.idSparePartCategory NOT IN(SELECT ID FROM ExclusionCat)
AND (@idSparePartCategories IS NULL
OR TSP.fiSparePartCategory IN(
SELECT Item From dbo.Split(@idSparePartCategories,',')
)
)
AND (@idSpareParts IS NULL
OR TSP.idSparePart IN(
SELECT Item From dbo.Split(@idSpareParts,',')
)
)
)
SELECT Category
--, Part
--, PartNumber
, (SELECT SUM(Inventory) FROM ReportSP WHERE ReportSP.fiTabSparePart = idSparePart GROUP BY fiTabSparePart) AS Inventory
, (SELECT SUM(GoodsIn) FROM ReportSP WHERE ReportSP.fiTabSparePart = idSparePart GROUP BY fiTabSparePart) AS GoodsIn
, (SELECT SUM(Ordered) FROM ReportSP WHERE ReportSP.fiTabSparePart = idSparePart GROUP BY fiTabSparePart) AS Ordered
, Claimed
, ClaimedReused
, Costsaving
, Count(*) AS PartCount
FROM ReportTSP
GROUP BY Category
)