#sql #sql-server #tsql #join
Вопрос:
У меня есть 2 таблицы:
Games tbl Official tbl
Id Ref1 Ref2 Ref3 RefId Name
------------------------ ---------------------
1 1 3 2 1 Jaz
2 2 1 3 2 Rog
3 1 2 3 3 Dan
Если выбрана игра, мне нужно получить имена ссылок в качестве отдельных записей для этой игры, например:
Game 1 - Ref1 = Jaz Game 2 - Ref1 = Rog
Ref2 = Dan Ref2 = Jaz
Ref3 = Rog Ref3 = Dan
Я попробовал sql ниже, но, похоже, он получает только Ref1, а не Ref2 или Ref3:
Select a.Ref1, a.Ref2, a.Ref3
From Games a
Inner Join Official b On a.Ref1 = b.RefId
Where a.Id = @Id
Ответ №1:
Вы должны присоединиться Games
к 3 копиям Official
:
SELECT g.Id,
o1.Name Name1,
o2.Name Name2,
o3.Name Name3
FROM Games g
INNER JOIN Official o1 ON g.Ref1 = o1.RefId
INNER JOIN Official o2 ON g.Ref2 = o2.RefId
INNER JOIN Official o3 ON g.Ref3 = o3.RefId
WHERE g.Id = ?;
Смотрите демонстрацию.
Кроме того, вы можете протестировать коррелированные подзапросы вместо соединений.
Иногда они обеспечивают лучшую производительность:
SELECT g.Id,
(SELECT o.Name FROM Official o WHERE o.RefId = g.Ref1) Name1,
(SELECT o.Name FROM Official o WHERE o.RefId = g.Ref2) Name2,
(SELECT o.Name FROM Official o WHERE o.RefId = g.Ref3) Name3
FROM Games g
WHERE g.Id = ?;
Комментарии:
1. отлично. Спасибо. Я думал, что пробовал это раньше, и это не сработало, но ваш ответ был правильным.
2. @mlg отлично, если это сработает. Кроме того, проверьте соответствующие подзапросы в моем отредактированном ответе. Не такие элегантные, но они могут быть лучше для производительности в больших наборах данных.
3. Я обязательно проверю другой способ. еще раз спасибо!
Ответ №2:
Вы должны присоединиться к каждой ссылке из официальной таблицы в вашем запросе
Select Ref1, a.Ref2, a.Ref3 From Games a
Left Join Official
b On a.Ref1 = b.RefId
OR a.Ref2 = b.RefId
OR a.Ref3 = b.RefId
Where a.Id = @Id
Комментарии:
1. Требование состоит в том, чтобы получить имена от официальных лиц, а не от рефкса.
Ответ №3:
Изначально, глядя на желаемые результаты с именами в отдельных строках, казалось, что вы хотите удалить данные, для которых cross apply
был бы применим следующий запрос с использованием:
select g.id GameId, o.refId, o.Name
from games g
cross apply (values (ref1,1), (ref2,2), (ref3,3))r(refId,seq)
join officials o on o.refId=r.RefId
where g.id=1
order by r.seq;
тем не менее, похоже, что вы ожидаете одну строку в игре с тремя столбцами, и в этом случае применимо то же самое, теперь также с операцией разворота.
Вы можете подумать, что это многословно по сравнению с более простым вариантом множественного присоединения, однако для конкретного идентификатора игры требуется прочитать каждую таблицу только один раз.
select GameId,
Max(case when seq=1 then name end) Ref1,
Max(case when seq=2 then name end) Ref2,
Max(case when seq=3 then name end) Ref3
from (
select g.id GameId, o.refId, o.Name, r.Seq
from games g
cross apply (values (ref1,1), (ref2,2), (ref3,3))r(refId,seq)
join officials o on o.refId=r.RefId
where g.id=1
)g
group by GameId;