SUM由两个不同的GROUP BY组成

时间:2012-03-02 12:19:58

标签: sql sql-server sql-server-2005 tsql

我从报告中得到了错误的结果。也许我错过了一些简单的东西。

该报告是一个内联表值函数,应该计算我们商店中的货物移动以及这些备件的索赔频率(在维修中更换)。

问题:商店表中的不同备件(让我们称之为SP)可以链接到“修复表”(TSP)中的相同备件。我需要SP中每个备件的货物移动以及TSP中每个不同备件的索赔计数。

这是相关部分的非常简化的摘录:

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

Ordered - 计数是正确的,但Claimed - 计数应为300而不是900,因为TspName ='1235-6044'。

我需要按Tsp.ID分组索赔计数,并按Sp.ID分组,以获取订单计数。但是在一个查询中如何?

修改:实际上TVF看起来像(请注意getOrderedgetClaimed是SVF,而我正在TSP的类别中选择外部选项):

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)
    ), Report AS(
        SELECT Cat.SparePartCategoryName AS Category
        ,TSP.SparePartDescription AS Part
        ,TSP.SparePartName AS PartNumber
        ,SP.Inventory
        ,Gambio.getGoodsIn(SP.idSparePart,@FromDate,@ToDate) GoodsIn
        ,Gambio.getOrdered(SP.idSparePart,@FromDate,@ToDate) Ordered
        --,CASE WHEN TSP.idSparePart IS NULL THEN 0 ELSE
        --  Gambio.getClaimed(TSP.idSparePart,@FromInvoiceDate,@ToInvoiceDate,@idClaimStatus,NULL)END AS Claimed
        ,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  Gambio.SparePart AS SP 
        INNER JOIN tabSparePart AS TSP ON SP.fiTabSparePart = TSP.idSparePart 
        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
    , SUM(Inventory)As InventoryCount
    , SUM(GoodsIn) As GoodsIn
    , SUM(Ordered) As Ordered
    --, SUM(Claimed) As Claimed
    , SUM(ClaimedReused)AS ClaimedReused
    , SUM(Costsaving) As Costsaving
    , Count(*) AS PartCount
    FROM Report
    GROUP BY Category
)

解决方案

感谢Aliostad,我通过先分组然后加入(实际TVF,减少到最低限度)来解决它:

WITH Report AS(
        SELECT Cat.SparePartCategoryName AS Category
        ,TSP.SparePartDescription AS Part
        ,TSP.SparePartName AS PartNumber
        ,SP.Inventory
        ,SP.GoodsIn
        ,SP.Ordered
        ,Gambio.getClaimed(TSP.idSparePart,@FromInvoiceDate,@ToInvoiceDate,@idClaimStatus,1) AS ClaimedReused
        ,Gambio.getCostSaving(TSP.idSparePart,@FromInvoiceDate,@ToInvoiceDate,@idClaimStatus) AS Costsaving
        FROM  (
            SELECT GSP.fiTabSparePart 
            ,SUM(GSP.Inventory)AS Inventory
            ,SUM(Gambio.getGoodsIn(GSP.idSparePart,@FromDate,@ToDate))AS GoodsIn
            ,SUM(Gambio.getOrdered(GSP.idSparePart,@FromDate,@ToDate))AS Ordered
            FROM Gambio.SparePart GSP
            GROUP BY GSP.fiTabSparePart
        )As SP
        INNER JOIN tabSparePart TSP ON  SP.fiTabSparePart = TSP.idSparePart
        INNER JOIN tabSparePartCategory AS Cat 
        ON Cat.idSparePartCategory=TSP.fiSparePartCategory
    )
    SELECT Category
    , SUM(Inventory)As InventoryCount
    , SUM(GoodsIn) As GoodsIn
    , SUM(Ordered) As Ordered
    , SUM(ClaimedReused)AS ClaimedReused
    , SUM(Costsaving) As Costsaving
    , Count(*) AS PartCount
    FROM Report
    GROUP BY Category

5 个答案:

答案 0 :(得分:3)

您先加入,然后进行GROUPing by。您需要先将其反转,然后再使用GROUP BY,然后再加入。

所以在我的子查询中,我首先分组,然后加入:

select 
    claimed,
    ordered 
from 
     #tsp 
inner JOIN
      (select 
             fitsp, 
             SUM(ordered) as ordered 
       from 
              #sp
        group by 
              fitsp) as SUMS           
on 
     SUMS.fiTsp = id;

答案 1 :(得分:3)

我认为你只需要选择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

答案 2 :(得分:1)

您的ctetspsp之间的内部联接,这意味着您查询的数据如下所示:

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

请注意TspIDTspNameClaimed如何重复。按TspName分组意味着数据分为两组,一组用于1235-6044,另一组用于1234-5678。第一组有3行用于运行聚合函数,第二组只有一行。这就是为什么你的sum(Claimed)会让你获得300 * 3 = 900。

正如Aliostad建议的那样,您应首先按TspID分组,然后执行Ordered的总和,然后加入tsp

答案 3 :(得分:1)

无需加入,只需进行选择:

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;

产地:

id  name        Claimed Ordered 
1   1235-6044   300 120 
2   1234-5678   400 60

- 编辑 -

根据附加信息,我可以尝试按照示例分割CTE以形成数据。我完全承认,Aliostad的方法可能会产生更清晰的查询,但这是使用子选择的尝试(完全失明):

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)希望它会给你一些关于替代方法的新思路。 / p>

答案 4 :(得分:0)

SELECT
tsp.name
,max(tsp.claimed) as claimed
,sum(sp.ordered) as ordered 
from #sp sp 
inner join #tsp tsp 
on sp.fiTsp=tsp.id
GROUP BY tsp.name