ROW_NUMBER() ORDER BY,不能在同一个 SELECT 语句中使用列

Posted

技术标签:

【中文标题】ROW_NUMBER() ORDER BY,不能在同一个 SELECT 语句中使用列【英文标题】:ROW_NUMBER() ORDER BY, can't use column within same SELECT statement 【发布时间】:2016-06-17 06:27:05 【问题描述】:

我在下面有一个调用视图来创建排名表的过程:

CREATE PROCEDURE [dbo].[League_Table_Insert]
    @LeagueName VARCHAR(30)
AS
SET NOCOUNT ON
BEGIN

    DECLARE @LeagueID INT

    SELECT 
    @LeagueID = LeagueID FROM dbo.League
    WHERE LeagueName = @LeagueName

    SELECT [TeamName], [Played], [Wins], [Loss], [Draws], [Points], [Goals_Scored], [Goals_Against], [Goal_Difference]  
    FROM League_Table
    WHERE LeagueID = @LeagueID
    ORDER BY Points DESC, Goal_Difference DESC;

END

查看:

CREATE VIEW League_Table
    AS
    SELECT f.LeagueID, t.TeamName, 
    SUM(
        CASE WHEN f.HomeScore IS NOT NULL THEN 1 ELSE 0 END
    ) AS Played,
        SUM(
        CASE        
            WHEN t.TeamID = f.HomeTeamID THEN
                --Home Fixture
                CASE
                 WHEN f.HomeScore > f.AwayScore THEN 1 
                 ELSE 0
                 END
            WHEN t.TeamID = f.AwayTeamID THEN
                CASE
                 WHEN f.AwayScore > f.HomeScore THEN 1
                 ELSE 0 
                 END
        END
        ) AS Wins, 
            SUM(
        CASE        
            WHEN t.TeamID = f.HomeTeamID THEN
                --Home Fixture
                CASE
                 WHEN f.HomeScore < f.AwayScore THEN 1 
                 ELSE 0
                 END
            WHEN t.TeamID = f.AwayTeamID THEN
                CASE
                 WHEN f.AwayScore < f.HomeScore THEN 1 
                 ELSE 0
                 END
        END
        ) AS Loss, 
        SUM(CASE WHEN f.HomeScore = f.AwayScore THEN 1 ELSE 0 END) as Draws, 
        SUM(
        CASE 
            WHEN t.TeamID = f.AwayTeamID THEN
                --Away Fixture
                CASE
                    WHEN f.AwayScore > f.HomeScore THEN 3
                    WHEN f.AwayScore = f.HomeScore THEN 1
                    ELSE 0
                END
            WHEN t.TeamID = f.HomeTeamID THEN
                --Home Fixture
                CASE
                    WHEN f.HomeScore > f.AwayScore THEN 3 
                    WHEN f.HomeScore = f.AwayScore THEN 1
                    ELSE 0
                END
        END
    ) AS Points, 
        SUM(
        CASE
            WHEN t.TeamID = f.HomeTeamID THEN f.HomeScore
            -- Home Fixture
            WHEN t.TeamID = f.AwayTeamID THEN f.AwayScore
            -- Away Fixture
            END
            ) AS Goals_Scored,

        SUM(
        CASE
            WHEN t.TeamID = f.HomeTeamID THEN f.AwayScore
            -- Home Fixture
            WHEN t.TeamID = f.AwayTeamID THEN HomeScore
            -- Away Fixture
            END
            ) AS Goals_Against,
         SUM(
          CASE
          WHEN t.TeamID = f.HomeTeamID THEN       
              CASE
              WHEN f.HomeScore IS NOT NULL THEN f.HomeScore - f.AwayScore
          -- Home Fixture
              END
          WHEN t.TeamID = f.AwayTeamID THEN 
              CASE
              WHEN f.AwayScore IS NOT NULL THEN f.AwayScore - f.HomeScore
          -- Away Fixture
              END
          END
        ) AS Goal_Difference
    FROM dbo.Team t
    --Season TBC
    INNER JOIN dbo.Fixture f ON t.TeamID IN (f.HomeTeamID, f.AwayTeamID)
    GROUP BY f.LeagueID, t.TeamName

下面是它的输出:

我想在视图中包含另一个字段,该字段将包含每支球队的联赛排名。我的问题是使用 ROW_NUMBER 时的 ORDER BY,因为我不确定将其设置为什么,因为我无法将其设置为“Points DESC”和“Goal_Difference DESC”,因为我在同一个 SELECT 语句中使用它创造它。我的问题是我应该在下面的代码中将 ORDER BY 设置为什么来输出正确的联赛位置?

ROW_NUMBER() OVER (PARTITION BY LeagueID ORDER BY ...)  AS Position,

【问题讨论】:

个人 - 我会看看你的数据模型,因为我认为你的很多问题都可以通过在保存游戏结果时简单地包含更多信息来解决。例如记录胜利/平局/失败而不仅仅是“HomeScore”和“AwayScore”会让你的很多查询变得更加简单——对于一个相当简单的模型来说,这似乎过于复杂。在最坏的情况下,计算列可以帮助您很多。 @Allan S. Hansen:我不同意。我认为数据模型是完美的,因为它包含没有任何冗余的纯结果。并且在表上构建视图使查询数据变得简单,尽管我会让视图不聚合,以便能够查询 select from view where Team_id = 5 例如。对于聚合,为方便起见,仍然可以基于非聚合视图构建视图。计算列(例如,WinningTeamIDLosingTeamIDHomeTeamIDAwayTeamID 或每个都为 null)当然值得在这里考虑)。 【参考方案1】:

最简单的方法可能是子查询(派生表):

CREATE VIEW League_Table AS
select 
  data.*, 
  row_number() over (partition by leagueid 
                     order by points desc, goal_difference desc) as position,
from
(
  SELECT f.LeagueID, t.TeamName, 
  SUM(
      CASE WHEN f.HomeScore IS NOT NULL THEN 1 ELSE 0 END
     ) AS Played,
  SUM(
  ...
  GROUP BY f.LeagueID, t.TeamName
) data

【讨论】:

【参考方案2】:

多选一个

select *, ROW_NUMBER() OVER (PARTITION BY LeagueID ORDER BY Points DESC, Goal_Difference DESC)  AS Position
    from <your select statement>

【讨论】:

以上是关于ROW_NUMBER() ORDER BY,不能在同一个 SELECT 语句中使用列的主要内容,如果未能解决你的问题,请参考以下文章

oracle的row_number() OVER (ORDER BY COL2 asc)和row_number() OVER (PARTITION BY COL1 ORDER BY COL2)的用法

ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) 是不是保留订单?

row_number() over (partition by....order by...)用法 分组排序

ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN DESC)函数的使用

去重 ROW_NUMBER() OVER(PARTITION BY 分组字段 ORDER BY 排序字段) RN

row_number() over(partition by a order by b desc) rn 用法