2010-11-22 4 views
2

У меня есть три таблицы: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) 

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

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

Спасибо!

ответ

2

Вам нужно добавить 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   
+0

Это работало отлично, спасибо! – meepmeep

+0

Добро пожаловать. –

1

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

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 

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

1

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

Спасибо - это тоже работает, а также сделал процесс очень понятным для меня - внешние соединения не были тем, что я хотел. – meepmeep

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