SQL Query选择底片

时间:2017-01-14 04:37:12

标签: sql sql-server

以下查询完全按预期工作,并获得我想要的结果。

有没有更好的方法来写这个?问题是"打印所有团队ID,团队与费城人队对战,但不打击勇士队#34;这两个表的设置如下:

游戏:gameID,homeTeamID,guestTeamID,日期

队: teamID,teamName,home,leagueName

homeTeamID和guestTeamID是Teams表的外键,gameID和teamID都是主键。目前使用sql server dialect。

我真的觉得我是以一种荒谬的方式写这篇文章的,而且我必须做一些我不知道的事情。

WITH philliesgames AS 
( 
       SELECT g.* 
       FROM   games g 
       JOIN   teams t 
       ON     g.hometeamid = t.teamid 
       OR     g.guestteamid = t.teamid 
       WHERE  t.teamname = 'Phillies'), bravesgames AS 
( 
       SELECT g.* 
       FROM   games g 
       JOIN   teams t 
       ON     g.hometeamid = t.teamid 
       OR     g.guestteamid = t.teamid 
       WHERE  t.teamname = 'Braves') 
( 
       SELECT guestteamid 
       FROM   philliesgames 
       WHERE  guestteamid <> 1 
       UNION 
       SELECT hometeamid 
       FROM   philliesgames 
       WHERE  hometeamid <> 1) 
EXCEPT 
       ( 
              SELECT guestteamid 
              FROM   bravesgames 
              UNION 
              SELECT hometeamid 
              FROM   bravesgames)

2 个答案:

答案 0 :(得分:1)

试试这个:

select
    IIF(t.teamid = g.hometeamid, g.guestteamid, g.hometeamid) id
from games g inner join teams t
on t.teamid in (g.hometeamid, g.guestteamid)
where t.teamname = 'Phillies'
except
select
    IIF(t.teamid = g.hometeamid, g.guestteamid, g.hometeamid)
from games g inner join teams t
on t.teamid in (g.hometeamid, g.guestteamid)
where t.teamname = 'Braves';

如果您的SQL Server版本不支持IIF,请改用CASE

IIF(t.teamid = g.hometeamid, g.guestteamid, g.hometeamid)

CASE t.teamid WHEN g.hometeamid THEN g.guestteamid ELSE g.hometeamid END

答案 1 :(得分:1)

这是另一种方法:

with teamGames(teamId, againstId) as (
    select homeTeamId, guestTeamId from games
    union
    select guestTeamId, homeTeamId from games
)
select teamId
from teamGames
group by teamId
having
        count(case when againstId =
                (select teamId from Teams where teamName = 'Phillies')
            then 1 end) >= 1
    and count(case when againstId =
                (select teamId from Teams where teamName = 'Braves')
            then 1 end) = 0;

编辑:为了完整起见,我想回来添加一些笔记。

首先,我有点怀疑SQL Server会在having子句中抱怨我的子查询,实际上它不允许这样做。我已经解决了以下问题。

with teamGames(teamId, againstId) as (
    select homeTeamId, guestTeamId from games
    union
    select guestTeamId, homeTeamId from games
)
select g.teamId
from
    teamGames as g
    inner join teams as t1 on t1.teamId = g.teamId
    inner join teams as t2 on t2.teamId = g.againstId
where t1.teamName not in ('Phillies', 'Braves')
group by g.teamId
having
        count(case when t2.teamName = 'Phillies' then 1 end) >= 1
    and count(case when t2.teamName = 'Braves'   then 1 end)  = 0;

我的查询版本具有巨大的优势,能够轻松添加任何数量的类似条件,而您的查询将变得更加复杂。将辅助数据添加到输出也更容易。但另外还有一点值得注意:您的unionexcept逻辑主要在关系中对称地对待每个团队。

在我的第二个查询中,我添加了一个检查,以防止Braves作为结果之一返回。勇敢者可以很好地发挥费城人队,而他们不可能自己发挥。根据您的定义,它们也可能是匹配的。只有隐含的常识,我们才假设勇士队不是你期望在结果中看到的团队。

您的查询必须处理费城人从未玩过勇士队的情况,否则不会被排除在名单之外。这似乎解释了<> 1检查。另一方面,没有其他任何明确消除勇士的东西,所以你必须深入挖掘。你会发现它被隐藏在except查询中,它有效地将勇士视为自己玩。这就是勇敢者如何被排除在考虑范围之外,很容易错过。

我希望你不要觉得这很迂腐。从表面上看,作为关于棒球的家庭作业问题,沿着这条路走下去是一个学术问题。我确实认为,在工作场所的其他环境中,您可以轻松地发现这一点非常重要且值得考虑。这是未被发现的错误的一种方式很容易蔓延到已部署的代码中。

在此处使用它:http://rextester.com/MIHL65545