2011-01-10 9 views
0

gibt es fünf vorhandenen Tabellen:SQL kommen über eine M: N Tabelle

(MAIL) 
id senderFK receiverFK text 

Die Sender und Empfänger sind in der MN Tabelle verwiesen:

(MN) 
id studentFK teacherFK guestFK 

Jeder Eintrag in MN nur gefüllt haben können id und eine der drei Fremdschlüsselspalten. Wenn eine Zeile zum Beispiel id 42 und 16 in studentFK hat, ist es referes dem Eintrag mit mit id 16 in der folgenden Tabelle:

(STUD) 
id name grade hasStudCard 

Die beiden anderen möglichen Tabellen für Sender/Empfänger sind:

(TEACH) 
id name age telephone 

und

(GUEST) 
id department 

Schüler, Lehrer und Gäste können Absender oder Empfänger einer E-Mail sein.

Jetzt möchte ich eine Ansicht erstellen, die die Mail-Tabelle mit allen Daten füllt, die die Absender und Empfänger haben können. Natürlich könnte ich eine volle äußere Verbindung auf Mail, MN und die drei anderen auf den IDs machen. Aber gibt es einen effizienteren Weg?

+1

Können Sie die Tabellenstruktur ändern? Diese Struktur ist kludgy und ist nicht in 3NF imo. – Leslie

+0

Es ist nur eine Abstraktion für eine kompliziertere Tabellenstruktur, also kommt es darauf an ... :) An welche Form denkst du? – Norbert

+0

So ist diese bestehende Struktur, oder denken Sie immer noch darüber nach? –

Antwort

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

Vielen Dank für Ihre Lösung! – Norbert

0

Kann Ihr RDBMS die Klausel 'WITH' verwenden?

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

Dies ist ziemlich unangenehm, weil die Struktur der Tabellen (STUD) (TEACH) und (GUEST) unterschiedlich ist. Sie können diese 'barbarische' volle äußere Verbindung versuchen:

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) 

, um Absenderdaten und eine ähnliche für die Empfänger zu extrahieren.

Wenn eine dieser Tabellen viel größer als die anderen Tabellen ist, wird die Leistung in der Regel reduziert, wenn die Tabelle verkleinert und der Join in der reduzierten Tabelle ausgeführt wird.

Verwandte Themen