t-sql внешнее объединение через три таблицы - PullRequest
2 голосов
/ 22 ноября 2010

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

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 строк независимо от содержимого таблицы событий.

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

Спасибо!

Ответы [ 3 ]

2 голосов
/ 22 ноября 2010

Вам нужно будет добавить 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        
1 голос
/ 22 ноября 2010

Если вам нужна строка для каждой комбинации person и eventtype, это предлагает CROSS JOIN. Чтобы получить продолжительность, нам нужно присоединиться к event, но это должно быть соединение OUTER, так как не всегда может быть строка. Ваше использование «total» предполагает, что для данной комбинации 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)
1 голос
/ 22 ноября 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

Кросс-соединение - это такое, где для каждой строки в левой таблице оно соединяется с каждымстрока в правой таблице.

...