внешнее соединение t-sql для трех таблиц

У меня есть три таблицы:

CREATE TABLE person
    (id int,
    name char(50))

CREATE TABLE eventtype
    (id int,
     description char(50))

CREATE TABLE event
    (person_id int,
     eventtype_id int,
     duration int)

Мне нужен один запрос, который дает мне список общей продолжительности каждого типа события для каждого человека, включая все нулевые записи. Например. если есть 10 человек и 15 различных типов событий, должно быть возвращено 150 строк, независимо от содержимого таблицы событий.

Я могу заставить внешнее соединение работать между двумя таблицами (например, продолжительность для всех типов событий), но не со вторым внешним соединением.

Спасибо!


person meepmeep    schedule 22.11.2010    source источник


Ответы (3)


Вам нужно будет добавить CROSS APPLY к миксу, чтобы получить несуществующие отношения.

SELECT  q.name, q.description, SUM(q.Duration)
FROM    (
          SELECT  p.Name, et.description, Duration = 0
          FROM    person p
                  CROSS APPLY eventtype et
          UNION ALL        
          SELECT  p.Name, et.description, e.duration
          FROM    person p
                  INNER JOIN event e ON e.person_id = p.id
                  INNER JOIN eventtype et ON et.id = e.eventtypeid        
        ) q
GROUP BY
        q.Name, q.description        
person Lieven Keersmaekers    schedule 22.11.2010

Вы можете перекрестно объединить человека и тип события, а затем просто соединить результат с таблицей событий:

SELECT
   p.Name,
   et.Description,
   COALESCE(e.duration,0)
FROM
   person p
      cross join
   eventtype et
      left join
   event e
      on
         p.id = e.person_id and
         et.id = e.eventtype_id

Перекрёстное соединение — это когда каждая строка в левой таблице соединяется с каждой строкой в ​​правой таблице.

person Damien_The_Unbeliever    schedule 22.11.2010

Если вам нужна строка для каждой комбинации person и eventtype, это предлагает CROSS JOIN. Чтобы получить продолжительность, нам нужно присоединиться к event, но это должно быть соединение OUTER, поскольку строка может быть не всегда. Ваше использование «всего» предполагает, что для данной комбинации person и event может быть более одного event, поэтому нам также понадобится SUM.

Образец данных:

insert person values ( 1, 'Joe' )
insert person values ( 2, 'Bob' )
insert person values ( 3, 'Tim' )

insert eventtype values ( 1, 'Cake' )
insert eventtype values ( 2, 'Pie' )
insert eventtype values ( 3, 'Beer' )

insert event values ( 1, 1, 10 ) 
insert event values ( 1, 2, 10 ) 
insert event values ( 1, 2, 5 ) 
insert event values ( 2, 1, 10 ) 
insert event values ( 2, 2, 7 ) 
insert event values ( 3, 2, 8 ) 
insert event values ( 3, 3, 16 ) 
insert event values ( 1, 1, 10 ) 

Запрос:

SELECT
    PET.person_id
    , PET.person_name
    , PET.eventtype_id
    , PET.eventtype_description
    , ISNULL(SUM(E.duration), 0) total_duration
FROM
    (
    SELECT
        P.id person_id
        , P.name person_name
        , ET.id eventtype_id
        , ET.description eventtype_description
    FROM
        person P
        CROSS JOIN eventtype ET
    ) PET
    LEFT JOIN event E ON PET.person_id = E.person_id
                     AND PET.eventtype_id = E.eventtype_id
GROUP BY
    PET.person_id
    , PET.person_name
    , PET.eventtype_id
    , PET.eventtype_description

Выход:

person_id   person_name eventtype_id eventtype_description total_duration
----------- ----------- ------------ --------------------- --------------
1           Joe         1            Cake                  20
1           Joe         2            Pie                   15
1           Joe         3            Beer                  0
2           Bob         1            Cake                  10
2           Bob         2            Pie                   7
2           Bob         3            Beer                  0
3           Tim         1            Cake                  0
3           Tim         2            Pie                   8
3           Tim         3            Beer                  16
Warning: Null value is eliminated by an aggregate or other SET operation.

(9 row(s) affected)
person AakashM    schedule 22.11.2010
comment
Спасибо - это тоже работает, а также сделало процесс очень понятным для меня - внешние соединения были не тем, что я хотел. - person meepmeep; 22.11.2010