2011-01-10 3 views
0

существует пять существующих таблиц:SQL присоединиться над M: N таблицу

(MAIL) 
id senderFK receiverFK text 

Отправители и приемники упоминаться в MN таблице:

(MN) 
id studentFK teacherFK guestFK 

Каждая запись в MN могут только залили id и один из трех столбцов внешнего ключа. Если одна строка, например, имеет id 42 и 16 в studentFK, он referes к входу с с id 16 в следующей таблице:

(STUD) 
id name grade hasStudCard 

Два других возможных таблиц для отправителей/приемники:

(TEACH) 
id name age telephone 

и

(GUEST) 
id department 

Студенты, учителя и гость могут быть отправителем или получателем почты.

Теперь я хочу создать представление, которое заполняет почтовую таблицу всеми данными, которые могут иметь отправители и получатели. Конечно, я мог бы сделать полное внешнее соединение на Mail, MN и три других на идентификаторах. Но есть ли более эффективный способ сделать это?

+1

Вы можете изменить структуру таблицы? Эта структура является kludgy и не находится в 3NF imo. – Leslie

+0

Это просто абстракция для более сложной структуры таблицы, так что это зависит ... :) В какой форме вы думаете? – Norbert

+0

Так что это существующая структура, или вы все еще думаете об этом? –

ответ

1
select 
     m.id    as MailID 
    , m.text   as MailText 

    , snd.PersonType as SenderType 
    , snd.PersonID  as SenderID 
    , snd.Name   as SenderName 
    , snd.grade   as SenderGrade 
    , snd.hasStudCard as SenderHasStudCard 
    , snd.age   as SenderAge 
    , snd.telephone  as SenderTelephone 
    , snd.department as SenderDepartment 

    , rec.PersonType as ReceiverType 
    , rec.PersonID  as ReceiverID 
    , rec.Name   as ReceiverName 
    , rec.grade   as ReceiverGrade 
    , rec.hasStudCard as ReceiverHasStudCard 
    , rec.age   as ReceiverAge 
    , rec.telephone  as ReceiverTelephone 
    , rec.department as ReceiverDepartment 

from MAIL as m 
join 
(
    select 
      p.id 
     , case 
      when s.id is not null then 'Student' 
      when t.id is not null then 'Teacher' 
      when g.id is not null then 'Guest' 
      end  as PersonType 
     , coalesce(s.id, t.id, g.ID) as PersonID 
     , coalesce(s.Name, t.name, '') as Name 
     , grade 
     , hasStudCard 
     , age 
     , telephone 
     , department 
    from MN   as p 
    left join STUDENT as s on (s.id = p.studentFK and p.teacherFK is null and p.guestFK is null) 
    left join TEACH as t on (t.id = p.teacherFK and p.studentFK is null and p.guestFK is null) 
    left join GUEST as g on (g.id = p.guestFK and p.studentFK is null and p.teacherFK is null) 
) as snd on snd.id = m.senderFK 
join 
(
    select 
      p.id 
     , case 
      when s.id is not null then 'Student' 
      when t.id is not null then 'Teacher' 
      when g.id is not null then 'Guest' 
      end  as PersonType 
     , coalesce(s.id, t.id, g.ID) as PersonID 
     , coalesce(s.Name, t.name, '') as Name 
     , grade 
     , hasStudCard 
     , age 
     , telephone 
     , department 
    from MN   as p 
    left join STUDENT as s on (s.id = p.studentFK and p.teacherFK is null and p.guestFK is null) 
    left join TEACH as t on (t.id = p.teacherFK and p.studentFK is null and p.guestFK is null) 
    left join GUEST as g on (g.id = p.guestFK and p.studentFK is null and p.teacherFK is null) 
) as rec on rec.id = m.receiverFK 
; 
+0

Большое спасибо за ваше решение! – Norbert

0

Может ли ваша РСУБД использовать предложение «WITH»?

with 
mnView as (
select 
    id mnId, 
    CASE 
    WHEN MN.studentFK IS NOT NULL THEN 'S' 
    WHEN MN.teacherFK IS NOT NULL THEN 'T' 
    WHEN MN.guestFK IS NOT NULL THEN 'G' 
    ELSE NULL 
    END mnType, 
    CASE 
    WHEN MN.studentFK IS NOT NULL THEN MN.studentFK 
    WHEN MN.teacherFK IS NOT NULL THEN MN.teacherFK 
    WHEN MN.guestFK IS NOT NULL THEN MN.guestFK 
    ELSE NULL 
    END refId 
    from MN 
), 
mnDetailView as (
select mnId, mnType, STUD.name, STUD.grade, STUD.hasStudCard, 
    NULL age, NULL telephone, NULL department 
from mnView 
    join STUD on STUD.id = mnView.refId 
where mnView.mnType = 'S' 
union all 
select mnId, mnType, TEACH.name, NULL grade, NULL hasStudCard, 
    TEACH.age, TEACH.telephone, NULL department 
from mnView 
    join TEACH on TEACH.id = mnView.refId 
where mnView.mnType = 'T' 
union all 
select mnId, mnType, NULL name, NULL grade, NULL hasStudCard, 
    NULL age, NULL telephone, GUEST.department 
from mnView 
    join GUEST on GUEST.id = mnView.refId 
where mnView.mnType = 'G' 
) 
select 
    MAIL.id, 
    MAIL.text, 
    sender.mnId senderMnId, sender.mnType senderMnType, sender.name senderName, 
    /* sender.grade senderGrade, ... and so on */ 
    receiver.mnId receiverMnId, receiver.mnType receiverMnType, receiver.name 
    /* receiver.grade receiverGrade, ... and so on */ 
receiverName 
from MAIL 
    join mnDetailView sender on sender.mnId = MAIL.senderFK 
    join mnDetailView receiver on receiver.mnId = MAIL.receiverFK 
0

Это довольно неудобно, потому что структура таблиц (STUD) (TEACH) и (ГОСТЕВАЯ) различна. Вы можете попробовать это «варварское» полное внешнее соединение:

SELECT (MAIL).id, (MAIL).text, (STUD).id, (STUD).name, (STUD).grade, (STUD).hasStudCard, (TEACH).id, (TEACH).name, (TEACH).age, (TEACH).telephone, (GUEST).id, (GUEST).department FROM (MAIL), (MN), (STUD), (TEACH), (GUEST) WHERE (MAIL).senderFK = (MN).id AND ((MN).studentFK = (STUD).id OR (MN).teacherFK = (TEACH).id OR (MN).guestFK = (GUEST).id) 

для извлечения данных отправителей и аналогичных для приемников.

В общем, если одна из этих таблиц намного больше, чем другие, уменьшение ее размера и выполнение соединения на уменьшенной таблице улучшит производительность.

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