如何选择某些行

时间:2016-06-28 07:42:41

标签: sql sql-server

我想在两个联赛之间创建一个促销和降级,其中LeagueID 2的前两个队员升级到LeagueID 1,而LeagueID 1的最后两个队伍降到{{1} }}

我的问题是如何选择那些球队,记住每个联赛的球队数量可能会在未来发生变化,所以我不能让降级球队在位置上使用where子句。我可以使用where子句来促进LeagueID 2中的位置1和2的问题,但是如果有一种方法可以从选择和计数中进行,那么我也将使用该方法。

我知道当我们选择正确的团队时我需要做的就是更新他们的LeagueIDs。

enter image description here

最新消息:

LeagueID 2

'球队'表:此表是所有球队的参考,以及他们参加的联赛:

UPDATE dbo.League
SET LeagueId = 2
WHERE LeagueId  = 1
AND Position IN
(
    SELECT TOP 2 Position
    FROM dbo.League_Table
    WHERE LeagueID = 1
    ORDER BY Position DESC
)

UPDATE dbo.League
SET LeagueId = 1
WHERE LeagueId  = 2
AND Position IN
(
    SELECT TOP 2 Position
    FROM dbo.League_Table
    WHERE LeagueID = 2
    ORDER BY Position
)

'联赛'表:参考所有联赛:

CREATE TABLE [dbo].[Team]
(
    [TeamID] TINYINT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
    [TeamAbbreviation] CHAR(3) UNIQUE, 
    [TeamName] VARCHAR(50) UNIQUE, 
    [LeagueID] TINYINT CONSTRAINT FK_Team_League FOREIGN KEY REFERENCES League(LeagueID), 
    [CountryID] TINYINT CONSTRAINT FK_Team_Country FOREIGN KEY REFERENCES Country(CountryID)
)

'League_Table'表:这是从视图组成的联赛表(如上面的屏幕截图所示):

CREATE TABLE [dbo].[League]
(
    [LeagueID] TINYINT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
    [LeagueName] VARCHAR(30) UNIQUE, 
    [MinLeagueWeight] INT,
    [MaxLeagueWeight] INT,
    [CountryID] TINYINT CONSTRAINT FK_League_Country FOREIGN KEY REFERENCES Country(CountryID), 
    [ParentLeagueID] TINYINT CONSTRAINT FK_League_ParentLeague FOREIGN KEY REFERENCES League(LeagueID)
)

3 个答案:

答案 0 :(得分:1)

如果你想在不同的联盟中动态使用它,你也可以使用RANK():

DECLARE @TABLE TABLE(league int, name varchar(10), position int);

INSERT INTO @TABLE
VALUES (1, 'Team A', 1),
       (1, 'Team B', 2),
       (1, 'Team C', 3),
       (1, 'Team D', 4),
       (1, 'Team E', 5),
       (1, 'Team F', 6),
       (1, 'Team G', 7),
       (1, 'Team H', 8),
       (1, 'Team I', 9),
       (1, 'Team J', 10),
       (1, 'Team K', 11),
       (2, 'Team A', 1),
       (2, 'Team B', 2),
       (2, 'Team C', 3),
       (2, 'Team D', 4),
       (2, 'Team E', 5),
       (2, 'Team F', 6),
       (2, 'Team G', 7),
       (2, 'Team H', 8),
       (2, 'Team I', 9),
       (2, 'Team J', 10),
       (2, 'Team K', 11);

SELECT league, name, position
FROM (SELECT *
           , RANK() OVER (PARTITION BY league ORDER BY position ASC) AS TopRank
           , RANK() OVER (PARTITION BY league ORDER BY position DESC) AS BottomRank
      FROM   @TABLE) RankedResults
WHERE TopRank <= 2
   OR BottomRank <= 2;

结果:

league      name       position
----------- ---------- -----------
1           Team K     11
1           Team J     10
1           Team B     2
1           Team A     1
2           Team K     11
2           Team J     10
2           Team B     2
2           Team A     1

编辑:TopRanked字段显然不是真正需要的,因为你可以只过滤位置,但作为一种解释我的方法的目的。

答案 1 :(得分:0)

无论有多少

,您都可以为底部两个下降
SELECT TOP 2 * 
FROM Teams 
WHERE LeagueID = 1 
ORDER BY Position DESC

(旁注:我希望您的Position字段是计算出来的,因为如果您保留它可能会影响数据的完整性,那么

你的2个问题很好,尽管可能,但将它们组合成一个查询将不太清楚。您只是在子查询

中缺少WHERE子句
UPDATE dbo.League
SET LeagueId = 2
WHERE LeagueId  = 1
AND Position IN
(
    SELECT TOP 2 Position
    FROM dbo.League 
    WHERE LeagueID = 1
    ORDER BY Position DESC
)

UPDATE dbo.League
SET LeagueId = 1
WHERE LeagueId  = 2
AND Position IN
(
    SELECT TOP 2 Position
    FROM dbo.League 
    WHERE LeagueID = 2
    ORDER BY Position
)

另一个尝试 - 这次只有一个查询。 H / T给@Jens提供测试用例。

如果你首先弄清楚每个球队的联赛位置如何变化:

SELECT LeagueID, TeamName, case
    when league>1 AND RANK() OVER (PARTITION BY league ORDER BY position ASC) <= 2 THEN -1
    when league<2 AND RANK() OVER (PARTITION BY league ORDER BY position DESC) <= 2 THEN 1
    else 0
end as leaguechange
FROM dbo.League_Table

(注意我在那里增加了2个条款 - league>1以阻止球队晋级联赛0和league<2以阻止球队降级到联赛3 - 这两个都可以调整相应地)

完成后,它可以在单个UPDATE中用作子查询:

UPDATE dbo.Team
SET LeagueID = LeagueID + leaguechange
FROM (
    SELECT LeagueID, TeamName, case
        when league>1 AND RANK() OVER (PARTITION BY leagueID ORDER BY position ASC) <= 2 THEN -1
        when league<2 AND RANK() OVER (PARTITION BY leagueID ORDER BY position DESC) <= 2 THEN 1
        else 0
    end as leaguechange
    FROM dbo.League_Table
) c
INNER JOIN dbo.Team t
 ON c.LeagueId = t.LeagueID
 AND c.TeamName = t.TeamName

答案 2 :(得分:0)

WITH NewLeague AS
(
   SELECT NewLeagueId = CASE WHEN LeagueId  = 1 THEN 2 ELSE 1 END, *
   FROM dbo.League
   WHERE 
   (
     LeagueId  = 1
     AND Position IN
     (
       SELECT TOP 2 Position
       FROM dbo.League 
       ORDER BY Position DESC
     )
   )
   OR
   (
     LeagueId  = 2
     AND Position IN
     (
       SELECT TOP 2 Position
       FROM dbo.League 
       ORDER BY Position ASC
     )
   )
)
UPDATE NewLeague 
SET LeagueId = NewLeagueId

如果你想结合降级和升级的更新声明,可以使用:

{{1}}