Sql Соедините 2 таблицы получите несколько столбцов данных, ссылающихся на данные в другой таблице

#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;
 

рабочий пример скрипки