具有多对多关系的独特SUM

时间:2012-03-12 09:30:34

标签: sql sql-server-2005 tsql

这是一个后续问题os this。由于另一个回答了一个重要的部分(如何通过分区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添加到已分配给另一个T2(bbb)的aaa,因此它已经是{-1}}的一部分,其中T2-group的名称为{ {1}}。

那么,当他们已经是另一组的一部分时,我怎么能防止计数值两次呢?

修改

这是来自Nikola's answer的结果查询(实际上是表值函数的一部分)。请注意,我需要使用标量值函数来检索值:

T1SumPrice

不幸的是,它似乎跳过了一些T1记录,因此我得到了错误的结果

3 个答案:

答案 0 :(得分:3)

这样做的方法是过滤关系,以便除了第一个之外的所有关系。如果我正确地读了你的例子,对于bbb行,T1SumPrice应该是100,00,因为从关系你可以看出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并且不得不摆脱@。

编辑:尝试解释。

这是有效的,因为子查询 rel 只允许t2关系中的一个。我选择第一个id,但这取决于你的用例。正如其他人所说,还有其他选择,即相等或按比例分配。

答案 1 :(得分:2)

要在SUM列中提供T1价格而不是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

答案 2 :(得分:1)

由于问题不清楚究竟要实施什么规则来强制重复,我提供了以下方法:

;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