2017-01-14 4 views
1

Ниже представлен запрос, который работает точно так, как должен, и получает результаты, которые я хочу.SQL Query для выбора отрицательных значений

Есть ли лучший способ написать это? Вопрос гласит: «Печать всех teamIDs, где команда играла против Филлис, но не против Смельчаки» и двух таблиц устанавливаются следующим образом:

Игры: GameID, homeTeamID, guestTeamID, дата

команды: teamID, teamName, home, leagueName

homeTeamID и guestTeamID являются внешними ключами для таблицы команд, gameID и teamID являются первичными ключами. В настоящее время используется SQL-сервер диалект.

Мне действительно кажется, что я написал это нелепо, и должно быть что-то более короткое, я могу сделать то, о чем я не знаю.

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) 

ответ

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 
+0

Awesome! Спасибо, есть несколько вещей, которые я могу извлечь из этого. – ajthyng

1

Здесь «S альтернативный подход:

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; 

EDIT: Для полноты я хотел вернуться и добавить некоторые заметки.

Во-первых, я подозреваю, что 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; 

Моя версия запроса имеет огромное преимущество в возможности тривиальным добавить любое количество подобных условиях, когда ваша станет гораздо сложнее. Также проще добавить вспомогательные данные на выход. Но есть и еще один тонкий момент, который стоит отметить: логика union и except логически трактует каждую команду симметрично в отношениях.

В моем втором запросе я добавил чек, чтобы предотвратить возвращение Бравс в качестве одного из результатов. Бравс может очень хорошо играть Филлис, в то время как невозможно играть сами. В зависимости от вашего определения они тоже могут быть совпадением. Только неявный здравый смысл, который мы предполагаем, что Бравс - это не команда, которую вы ожидаете увидеть в результатах.

Ваш запрос должен был обрабатывать случай, когда Филлис никогда не играл Бравс и в противном случае не был бы исключен из списка. Кажется, это объясняет проверки <> 1. С другой стороны, нет ничего другого, что явно устраняет Бравс, поэтому вам нужно копать немного глубже. Где вы найдете его погребенным в запросе except, который эффективно лечит Бравс как сыгравший себя. Вот как Бравс снимается с рассмотрения, и его легко пропустить.

Надеюсь, вы не найдете это педантичным. На первый взгляд, как домашний вопрос о бейсболе, это немного академический, чтобы пойти по этой дороге. Я думаю, что в других местах на рабочем месте вы могли бы легко найти этот конкретный момент, чтобы быть очень актуальным и заслуживающим внимания. Это один из неоткрытых ошибок, которые легко обнаруживаются в развернутом коде.

Поиграйте с ним здесь: http://rextester.com/MIHL65545

Смежные вопросы