行计数器,具有两个不同列中的条件

时间:2015-06-19 09:39:20

标签: sql tsql

我有以下表格与运动结果(例如足球):

  

tblGoals(RowId,GameRowIdm PlayerRowId,TeamRowId,GoalMinute)

RowId | GameRowId | PlayerRowId | TeamRowId | GoalMinute
--------------------------------------------------------
1     | 1         | 1           | 1         | 25
2     | 1         | 2           | 2         | 45
3     | 1         | 3           | 1         | 66
  

tblPlayers(RowId,PlayerName)

RowId | PlayerName
------------------
1     | John Snow
2     | Frank Underwood
3     | Jack Bauer
  

tblGames(RowId,TeamHomeRowId,TeamGuestRowId)

RowId | TeamHomeRowId | TeamGuestRowId | GameDate
---------------------------------------------------
1     | 1             | 2              | 2015-01-01

现在我想得到所有目标的清单。列表应如下所示:

GoalMinute | PlayerName      | GoalsHome | GoalsGuest
-----------------------------------------------------
25         | John Snow       | 1         | 0
45         | Frank Underwood | 1         | 1
66         | Jack Bauer      | 2         | 1

GoalsHome和GoalsGuest应该是球队投篮目标的反击。所以例如如果你检查最后一行,主队的结果是2:1。 为了得到这个目标列表,我使用了这个声明:

SELECT  t_gol.GoalMinute,
        t_ply.PlayerName,
        CASE WHEN
            t_gol.TeamRowId = t_gam.TeamHomeRowId 
            THEN ROW_NUMBER()  OVER (PARTITION BY t_gam.TeamHomeRowId ORDER BY t_gam.TeamHomeRowId)
        END AS GoalsHome,
        CASE WHEN
            t_gol.TeamRowId = t_gam.TeamGuestRowId 
            THEN ROW_NUMBER()  OVER (PARTITION BY t_gam.TeamGuestRowId ORDER BY t_gam.TeamGuestRowId)
        END AS GoalsGuest
FROM    dbo.tblGoalsFussball AS t_gol
LEFT JOIN dbo.tblPlayersFussball AS t_ply ON (t_ply.RowId = t_gol.PlayerRowId)
LEFT JOIN dbo.tblGames AS t_gam ON (t_gam.RowId = t_gol.GameRowId)
WHERE   t_gol.GameRowId = @match_row

但我得到的是这里:

GoalMinute | PlayerName      | GoalsHome | GoalsGuest
-----------------------------------------------------
25         | John Snow       | 1         | NULL
45         | Frank Underwood | NULL      | 2
66         | Jack Bauer      | 3         | NULL

也许ROW_NUMBER()是错误的做法?

2 个答案:

答案 0 :(得分:1)

我认为最简单的方法是使用子查询..

SELECT 
  tgs.GoalMinute,
  tpl.PlayerName,
  ( SELECT 
        COUNT(t.RowId) 
    FROM 
        tblgoals AS t 
    WHERE t.GoalMinute <= tgs.GoalMinute 
        AND t.GameRowId = tgm.RowId
        AND t.TeamRowId = tgm.TeamHomeRowId
  ) AS HomeGoals,
  ( SELECT 
        COUNT(t.RowId) 
    FROM 
        tblgoals AS t 
    WHERE t.GoalMinute <= tgs.GoalMinute 
        AND t.GameRowId = tgm.RowId
        AND t.TeamRowId = tgm.TeamGuestRowId
  ) AS GuestGoals
FROM 
     tblgoals AS tgs
     JOIN tblplayers AS tpl ON tgs.RowId = tpl.RowId
     JOIN tblGames AS tgm ON tgm.RowId = tgs.GameRowId
ORDER BY tgs.GoalMinute

答案 1 :(得分:1)

我会使用sum()作为带窗口的聚合函数来执行运行总计,其中over ...子句适用于SQL Server 2012+。

select 
    g.RowId, g.GameDate, t.GoalMinute, p.PlayerName, 
    GoalsHome = COALESCE(SUM(case when TeamRowId = g.TeamHomeRowId then 1 end) OVER (PARTITION BY gamerowid ORDER BY goalminute),0),
    GoalsGuest = COALESCE(SUM(case when TeamRowId = g.TeamGuestRowId then 1 end) OVER (PARTITION BY gamerowid ORDER BY goalminute),0) 
from tblGoals t
join tblPlayers p on t.PlayerRowId = p.RowId
join tblGames g on t.GameRowId = g.RowId
order by t.GameRowId, t.GoalMinute

另一种方法(也适用于旧版本)是使用自连接并总结具有较低目标分数的行。为了便于阅读,我使用了一个通用的表格表达式,将目标分为两列,供家庭和客队使用:

;with t as (
    select 
       g.GoalMinute, g.PlayerRowId, g.GameRowId, 
       case when TeamRowId = ga.TeamHomeRowId then 1 end HomeGoals,
       case when TeamRowId = ga.TeamGuestRowId then 1 end GuestGoals
    from tblGoals g
    join tblGames ga on g.GameRowId = ga.RowId
)

select 
    g.RowId, g.GameDate, t.GoalMinute, p.PlayerName, 
    GoalsHome  = (select sum(coalesce(HomeGoals,0)) from t t2 where t2.GoalMinute <= t.GoalMinute and t2.GameRowId = t.GameRowId),
    GoalsGuest = (select sum(coalesce(GuestGoals,0)) from t t2 where t2.GoalMinute <= t.GoalMinute and t2.GameRowId = t.GameRowId)
from t
join tblPlayers p on t.PlayerRowId = p.RowId
join tblGames g on t.GameRowId = g.RowId
order by t.GameRowId, t.GoalMinute

CTE并不是必需的,你也可以使用派生表

Sample SQL Fiddle