现有五个表:
(MAIL)
id senderFK receiverFK text
发件人和收件人在{{1}}表格中引用:
MN
(MN)
id studentFK teacherFK guestFK
中的每个条目只能填充MN
和三个外键列中的一个。
例如,如果某一行在id
中有id
42和16,则它会引用下表中带有studentFK
16的条目:
id
发件人/收件人的另外两个可能的表是:
(STUD)
id name grade hasStudCard
和
(TEACH)
id name age telephone
学生,老师和客人可以是邮件的发件人或收件人。
现在我想创建一个视图,用发件人和收件人可以拥有的所有数据填充邮件表。当然,我可以在(GUEST)
id department
,Mail
以及其他三个关于ID的全外联接。但是有更有效的方法吗?
答案 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
;
答案 1 :(得分:0)
您的RDBMS可以使用'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
答案 2 :(得分:0)
这非常不舒服,因为桌子(STUD)(TEACH)和(GUEST)的结构不同。你可以试试这个'野蛮人'全外连接:
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)
为接收者提取发送者数据和类似的数据。
通常,如果其中一个表比其他表大得多,减小其大小并在缩减表上执行连接将提高性能。