СУММА двумя разными GROUP BY - PullRequest
2 голосов
/ 02 марта 2012

Я получаю неверный результат из своего отчета. Может быть, я упускаю что-то простое.

Отчет представляет собой встроенную табличную функцию, которая должна подсчитывать движение товара в нашем магазине и как часто эти запасные части запрашиваются (заменяются при ремонте).

Проблема: разные запасные части в мастер-таблице (назовем это 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 выглядит так (обратите внимание, что getOrdered и getClaimed являются 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 ]

3 голосов
/ 02 марта 2012

Я думаю, вам просто нужно выбрать Заявленный и добавить его в Группу, чтобы получить то, что вы ищете.

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
3 голосов
/ 02 марта 2012

Сначала вы ПРИСОЕДИНЯЕТЕСЬ, а затем ГРУППИРУЕТЕ. Вам нужно поменять его, сначала GROUP BY, а затем JOIN.

Итак, в моем подзапросе я сначала группируюсь, а затем присоединяюсь:

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 голос
/ 02 марта 2012

Не нужно вступать, просто выберите:

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 для формирования данных в соответствии с примером.Я полностью признаю, что подход Алиостада может привести к более чистому запросу, но вот попытка (полностью слепая) с использованием подвыбора:

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 для всех случаев), надеюсь, это даст вам несколько свежих мыслей для альтернативных подходов.

1 голос
/ 02 марта 2012

Ваш 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 и Claimed все повторяется.Группировка по TspName означает, что данные группируются в две группы: одна для 1235-6044 и одна для 1234-5678.Первая группа имеет 3 строки для запуска агрегатных функций, вторая группа только одна.Вот почему ваш sum(Claimed) получит вам 300 * 3 = 900.

Как подсказал Алиостад, вы должны сначала сгруппировать по TspID и сделать сумму Ordered и затем присоединиться к tsp.

0 голосов
/ 02 марта 2012
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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...