Отличная сумма с множеством отношений - PullRequest
0 голосов
/ 12 марта 2012

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

Как SUM в отношениях «многие ко многим», если «левая» сторона должна учитываться только один раз.

Рассмотрим следующие примеры данных, которые, надеюсь, объясняют мою проблему:

declare @t1 table (ID int,Price money, Name varchar(10))
declare @t2 table (ID int,Orders int,  Name varchar(10))
declare @relation  table (t1ID int,t2ID int)
insert into @t1 values(1, 200, 'AAA');
insert into @t1 values(2, 150, 'BBB');
insert into @t1 values(3, 100, 'CCC');
insert into @t2 values(1,25,'aaa');
insert into @t2 values(2,35,'bbb');
insert into @relation values(1,1);
insert into @relation values(2,1);
insert into @relation values(3,2);
-- following record will cause the "wrong" sum
insert into @relation values(2,2);

select
 T2.Name as T2Name
,T2.Orders As T2Orders
,T1Sum.Price As T1SumPrice
,T1.Price As T1HighestPrice
,T1.Name As T1HighestPrice_Name
FROM @t2 T2
INNER JOIN (
    SELECT Rel.t2ID
        ,Rel.t1ID
        ,ROW_NUMBER()OVER(Partition By Rel.t2ID Order By Price DESC)As PriceList
        ,SUM(Price)OVER(PARTITION BY Rel.t2ID) AS Price
        FROM @t1 T1 
        INNER JOIN @relation Rel ON Rel.t1ID=T1.ID
)AS T1Sum ON  T1Sum.t2ID = T2.ID AND t1Sum.PriceList = 1
INNER JOIN @t1 T1 ON T1Sum.t1ID=T1.ID

Фактический результат:

T2Name  T2Orders    T1SumPrice  T1HighestPrice  T1HighestPrice_Name
aaa         25          350,00          200,00          AAA
bbb         35          250,00          150,00          BBB

Желаемый результат:

T2Name  T2Orders    T1SumPrice  T1HighestPrice  T1HighestPrice_Name
aaa         25          350,00          200,00          AAA
bbb         35          100,00          150,00          BBB

Обратите внимание на разницу в T1SumPrice. Последняя запись в таблице отношений вставляет T1 в bbb, который уже был назначен другому T2 (aaa), следовательно, он уже является частью T1SumPrice для T2-группы с Name = aaa.

Так, как я могу предотвратить подсчет значений дважды, когда они уже являются частью другой группы?

Редактировать

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

select T2.idSparePart As T2_ID
,T2.PartNumber as T2_PartNumber
,Gambio.getGoodsIn(T2.idSparePart,@FromDate,@ToDate) AS GoodsIn
,Gambio.getOrdered(T2.idSparePart,@FromDate,@ToDate) AS Ordered
,T1Sum.ClaimedReused As T1SumPrice_ClaimedReused
,T1Sum.Costsaving As T1SumPrice_Costsaving
,T1.Price As T1HighestPrice
,T1.idSparePart AS T1HighestPrice_ID
,T1.SparePartName As T1HighestPrice_Number
,T1.SparePartDescription As T1HighestPrice_Name
,Cat.SparePartCategoryName As T1HighestPrice_Category
FROM Gambio.SparePart T2
INNER JOIN (
    SELECT Rel.fiSparePart
        ,Rel.fiTabSparePart
        ,ROW_NUMBER()OVER(Partition By Rel.fiSparePart Order By Price DESC)As PriceList
        ,SUM(Gambio.getMaterialQuantity(Rel.fiTabSparePart,NULL,NULL,@idClaimStatus,1))OVER(PARTITION BY Rel.fiSparePart) AS ClaimedReused
        ,SUM(Gambio.getCostSaving(Rel.fiTabSparePart,NULL,NULL,@idClaimStatus))OVER(PARTITION BY Rel.fiSparePart) AS Costsaving
        FROM tabSparePart T1 
        INNER JOIN 
          (select fiTabSparePart
            , fiSparePart
            from Gambio.trelSparePartClaimGroup relation
            where not exists (
                select null 
                from Gambio.trelSparePartClaimGroup rel 
                where rel.fiTabSparePart = relation.fiTabSparePart
                and rel.fiSparePart < relation.fiSparePart
            )
        )
        Rel ON Rel.fiTabSparePart=T1.idSparePart
)AS T1Sum ON  T1Sum.fiSparePart = T2.idSparePart AND t1Sum.PriceList = 1
INNER JOIN tabSparePart T1 ON T1Sum.fiTabSparePart=T1.idSparePart
INNER JOIN tabSparePartCategory AS Cat 
    ON Cat.idSparePartCategory=T1.fiSparePartCategory

К сожалению, кажется, что некоторые T1-записи пропущены, поэтому я получаю неправильный результат

Ответы [ 3 ]

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

Способ сделать это - отфильтровать отношения, чтобы пропустить все, кроме первого. И если я правильно прочитал ваш пример, T1SumPrice должен быть 100,00 для строки bbb, потому что из отношения вы видите, что, где t2id = 1, вы суммируете 200 + 150, а для t2id = 2 100 + 150, но 150 уже потрачено в предыдущей строке.

select
 T2.Name as T2Name
,T2.Orders As T2Orders
,T1Sum.Price As T1SumPrice
,T1.Price As T1HighestPrice
,T1.Name As T1HighestPrice_Name
FROM t2 T2
INNER JOIN (
    SELECT Rel.t2ID
        ,Rel.t1ID
        ,ROW_NUMBER()OVER(Partition By Rel.t2ID Order By Price DESC)As PriceList
        ,SUM(Price)OVER(PARTITION BY Rel.t2ID) AS Price
        FROM t1 T1 
        INNER JOIN 
          (select t1id, t2id
             from Relation
            where not exists (select null from relation test where test.t1id = relation.t1id
                              and test.t2id < relation.t2id)
        )
        Rel ON Rel.t1ID=T1.ID
)AS T1Sum ON  T1Sum.t2ID = T2.ID AND t1Sum.PriceList = 1
INNER JOIN t1 T1 ON T1Sum.t1ID=T1.ID

P.S. Я использовал Sql Fiddle и должен был избавиться от @.

РЕДАКТИРОВАТЬ: попытка объяснения.

Это работает, потому что подзапросом разрешено только одно из отношений t2 rel . Я выбираю первый идентификатор, но это зависит от вашего варианта использования. Как уже говорили другие, есть и другие варианты, равные или пропорциональные.

2 голосов
/ 12 марта 2012

Чтобы пропорционально оценить цену T1 через столбец SUM, но не столбец MAX, попробуйте следующее:

select
 MAX(T2.Name) as T2Name
,MAX(T2.Orders) As T2Orders
,SUM(T1Sum.ProRataPrice) As T1SumPrice
,MAX(T1Sum.Price) As T1HighestPrice
,MAX(CASE WHEN PriceList=1 THEN T1Sum.Name END) As T1HighestPrice_Name
FROM @t2 T2
INNER JOIN (
  SELECT Rel.t2ID
        ,Rel.t1ID
        ,Name
        ,ROW_NUMBER()OVER(Partition By Rel.t2ID Order By Price DESC)As PriceList
        ,Price
        ,Price / COUNT(*)OVER(PARTITION BY Rel.t1ID) AS ProRataPrice
        FROM @t1 T1 
        INNER JOIN @relation Rel ON Rel.t1ID=T1.ID
)AS T1Sum ON  T1Sum.t2ID = T2.ID 
GROUP BY T2.ID
1 голос
/ 12 марта 2012

Поскольку неясно, какие именно правила следует применять для выявления дубликатов, я предлагаю следующий подход:

;WITH T1Sum AS
(   SELECT  Rel.t2ID,
            Rel.t1ID,
            ROW_NUMBER() OVER(PARTITION BY Rel.t2ID ORDER BY Price / Relations DESC) As PriceList,
            SUM(Price / Relations) OVER (PARTITION BY t2ID) [Price]
    FROM    @t1 T1 
            INNER JOIN 
            (   SELECT  *,COUNT(*) OVER(PARTITION BY t1ID) [Relations]
                FROM    @Relation
            ) rel
                ON Rel.t1ID = T1.ID
)
SELECT  T2.Name as T2Name,
        T2.Orders As T2Orders,
        T1Sum.Price As T1SumPrice,
        T1.Price As T1HighestPrice,
        T1.Name As T1HighestPrice_Name
FROM    @t2 T2
        INNER JOIN T1Sum 
            ON T1Sum.t2ID = T2.ID 
            AND t1Sum.PriceList = 1
        INNER JOIN @t1 T1 
            ON T1Sum.t1ID = T1.ID

Это распределяет цену равномерно через дубликаты отношений, поэтому для примера она вернет:

T2Name  T2Orders    T1SumPrice  T1HighestPrice  T1HighestPrice_Name
aaa         25          275,00          200,00          AAA
bbb         35          175,00          150,00          BBB
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...