在不同顺序的对中运行聚合列

时间:2013-05-23 06:35:20

标签: sql-server-2008

如果我有这样的数据:

Id, Team1, Team2, Score1, Score2
--------------------------------
1,  Aaa,   Bbb,   10,     8 
2,  Aaa,   Bbb,   6,      8 
3,  Aaa,   Bbb,   6,      5 
4,  Bbb,   Aaa,   9,      7 
5,  Aaa,   Ccc,   12,     6

如何获得各个团队之间得分差异的列(运行汇总)? 例如:

Id, Team1, Team2, Score1, Score2  Abs(DIFF)
--------------------------------  ---------
1,  Aaa,   Bbb,   10,     8       2
2,  Aaa,   Bbb,   6,      8       0
3,  Aaa,   Bbb,   6,      5       1
4,  Bbb,   Aaa,   7,      9       3       
5,  Aaa,   Ccc,   12,     6       6


请注意以上示例中的两件事:

  • 对之间的团队顺序可能会有所不同(如第1行和第4行之间)
  • 表格可能包含许多团队对

是否可以在不使用游标或更新技巧的情况下获取此DIFF列? 查询必须在SQL Server 2008上运行。

我很少做DB工作,欢迎这么简单的解释。

更新其他说明:

  • 在第一行,DIFF是2,因为Aaa队赢了两分
  • 在第二行,DIFF为0,因为这次Bbb团队赢了两分
  • 在第三行,DIFF为1,因为Aaa队再次获胜(一分)
  • 在第四排DIFF为3,因为Aaa队再次获胜(两分)

因此,通过查看DIFF值,人们应该能够回答诸如“团队之间当前得分差异是什么?”这样的问题。

3 个答案:

答案 0 :(得分:2)

使用您的第二个样本数据(第3行绑定在第一个样本中,第4行绑定分数开关侧):

declare @t table (Id int not null,Team1 char(3) not null,Team2 char(3) not null,
    Score1 int not null,Score2 int not null)
insert into @t(Id, Team1, Team2, Score1, Score2) values
(1,  'Aaa',   'Bbb',   10,     8), 
(2,  'Aaa',   'Bbb',   6,      8), 
(3,  'Aaa',   'Bbb',   6,      5), 
(4,  'Bbb',   'Aaa',   7,      9), 
(5,  'Aaa',   'Ccc',   12,     6)

;With NormTeams as (
    select Id,
        CASE WHEN Team1 < Team2 THEN Team1 ELSE Team2 END as Team1,
        CASE WHEN Team1 < Team2 THEN Team2 ELSE Team1 END as Team2,
        CASE WHEN Team1 < Team2 THEN Score1 ELSE Score2 END as Score1,
        CASE WHEN Team1 < Team2 THEN Score2 ELSE Score1 END as Score2,
        (Score1 - Score2) * CASE WHEN Team1 < Team2 THEN 1 ELSE -1 END as ScoreDiff
    from @t
), MatchingTeams as (
    select *,ROW_NUMBER() OVER (PARTITION By Team1,Team2 ORDER BY ID) as rn
    from NormTeams
)
select *,
 (SELECT SUM(ScoreDiff) from MatchingTeams mt2 where
      mt2.Team1 = mt1.Team1 and mt2.Team2 = mt1.Team2 and
      mt2.rn <= mt1.rn) as RunningDiff
from MatchingTeams mt1

遗憾的是,在您使用2012 windowed aggregates之前,没有什么可以使它更整洁。

结果:

Id          Team1 Team2 Score1      Score2      ScoreDiff   rn                   RunningDiff
----------- ----- ----- ----------- ----------- ----------- -------------------- -----------
1           Aaa   Bbb   10          8           2           1                    2
2           Aaa   Bbb   6           8           -2          2                    0
3           Aaa   Bbb   6           5           1           3                    1
4           Aaa   Bbb   9           7           2           4                    3
5           Aaa   Ccc   12          6           6           1                    6

你会注意到我做的第一件事就是显而易见的 - 如有必要,可以转换团队和分数,以便查询的其余部分可以假设他们以一致的顺序出现

答案 1 :(得分:0)

你可以试试这个:

编辑:修复了team1&amp; team2交换。

; WITH CTE AS (
    SELECT
        Id
        , Team1
        , Team2
        , Score1
        , Score2
        , ROW_NUMBER() OVER (PARTITION BY X.Teams ORDER BY ???) AS Row
    FROM MyTable
    CROSS APPLY (
        SELECT
            Team1 + '_' + Team2 -- Use something else than '_' if this caracter can exist in team's names
        WHERE Team1 < Team2
        UNION ALL
        SELECT
            Team2 + '_' + Team1
        WHERE Team1 > Team2
    ) AS X(Teams)
)
SELECT
        T1.Id
        , T1.Team1
        , T1.Team2
        , T1.Score1
        , T1.Score2
        , ABS((T1.Score1 + ISNULL(T2.Score1, 0)) - (T1.Score2 + ISNULL(T2.Score2, 0))) AS Abs(DIFF)
FROM CTE AS T1
OUTER APPLY (
    SELECT
        SUM(T2.Score1) AS Score1
        , SUM(T2.Score2) AS Score2
    FROM CTE AS T2
    WHERE T2.Teams = T1.Teams
    AND T2.Row < T1.Row
) AS T2

答案 2 :(得分:0)

试试这个:

;WITH CTE as
(
select id,Team1,Team2,Score1,Score2,0 as RS1,0 as RS2,ABS(Score1-Score2) as DIFF from Table1 where id=1
UNION ALL
select t1.id,t1.Team1,t1.Team2,t1.Score1,t1.Score2,c.score1+t1.Score1,c.score2+t1.Score2,ABS((c.score1+t1.Score1)-(c.score2+t1.Score2)) as DIFF 
from Table1 t1 inner join CTE c 
on c.id+1=t1.id and ((t1.Team1 = c.team1 and t1.Team2 = c.Team2) or (t1.Team2 = c.team1 and t1.Team1 = c.Team2)) 
)
,CTE1 As
(
select * from CTE
union
select id,Team1,Team2,Score1,Score2,0,0,ABS(Score1-Score2) as DIFF from Table1 where id not in(select id from CTE)
)

select id,Team1,Team2,Score1,Score2,DIFF from CTE1