PostgreSQL 10.1
我有下面的SQL命令,它们几乎是 足够好了-但不是完全。 (标题是我能想到的最好的:))
想法是拥有一个可以拥有0,1或更多办事处的专业。每个办事处可以有0,1或更多的顾问(即姓/名)。
目标是始终在每个记录上显示专业名称。 如果该专业有任何办公室,那么该办公室需要(无重复)出现该专业。 (可能会列出一个以上的办公室,但不包括一个专业)。 如果列出的办公室有任何顾问,则应在办公室列出该顾问。 具有顾问的办公室应始终与该顾问一起列出。
根据上述要求,以下SQL本质上会生成太多条记录。也就是说,在研究输出时:
如何编写SQL以正确产生所需的结果? (或者编程方法会更好吗?)
在此先感谢您的帮助。
select s.speciality_name, f.office_name, f.street, f.city, f.state, f.zipcode, f.phone, f.fax, cs.lastname, cs.firstname, 0 as status, s.recid
from speciality s
left join office_speciality os on os.speciality_recid = s.recid
left join office f on f.recid = os.office_recid
left join consultant_office co on co.office_recid = f.recid
left join consultant cs on cs.recid = co.consultant_recid and cs.speciality_recid = s.recid
group by speciality_name, office_name, street, city, state, zipcode, phone, fax, lastname, firstname, s.recid
order by s.speciality_name, f.office_name, cs.lastname, cs.firstname;
编辑:使用下面的代码仍然会导致存在完整行时产生过多的部分行。第12行和第14行:
with office_speciality_consultants AS (
select distinct on (os.office_recid, os.speciality_recid, cs.recid)
os.office_recid, os.speciality_recid,
f.office_name, f.street, f.city, f.state, f.zipcode, f.phone, f.fax,
cs.lastname, cs.firstname
from office_speciality os
join office f on f.recid = os.office_recid
left join consultant_office co on co.office_recid = f.recid
left join consultant cs on cs.recid = co.consultant_recid
and cs.speciality_recid = os.speciality_recid
order by os.office_recid, os.speciality_recid, cs.recid, f.office_name, cs.lastname, cs.firstname
)
select
s.speciality_name,
ofc.office_name, ofc.street, ofc.city, ofc.state, ofc.zipcode, ofc.phone, ofc.fax,
ofc.lastname, ofc.firstname,
0 as status, s.recid
from speciality s
join office_speciality_consultants ofc ON ofc.speciality_recid = s.recid
order by s.speciality_name, ofc.office_name;
答案 0 :(得分:1)
如果我们需要所有办公室,但只需要一位办公室顾问,那么我相信以下人员应该起作用
with office_speciality_consultants AS (
select distinct on (os.office_recid, os.speciality_recid, cs.recid)
os.office_recid, os.speciality_recid,
f.office_name, f.street, f.city, f.state, f.zipcode, f.phone, f.fax,
cs.lastname, cs.firstname
from office_speciality os
join office f on f.recid = os.office_recid
left join consultant_office co on co.office_recid = f.recid
left join consultant cs on cs.recid = co.consultant_recid
and cs.speciality_recid = os.speciality_recid
order by os.office_recid, os.speciality_recid, cs.recid, f.office_name, cs.lastname, cs.firstname
)
select
s.speciality_name,
ofc.office_name, ofc.street, ofc.city, ofc.state, ofc.zipcode, ofc.phone, ofc.fax,
ofc.lastname, ofc.firstname,
0 as status, s.recid
from speciality s
join office_speciality_consultants ofc ON ofc.speciality_recid = s.recid
order by ofc.office_name;
答案 1 :(得分:0)
使用LEFT JOIN
更改您的上一个INNER JOIN
select s.speciality_name, f.office_name, f.street, f.city, f.state, f.zipcode, f.phone, f.fax, cs.lastname, cs.firstname, 0 as status, s.recid
from speciality s
left join office_speciality os on os.speciality_recid = s.recid
left join office f on f.recid = os.office_recid
left join consultant_office co on co.office_recid = f.recid
inner join consultant cs on cs.recid = co.consultant_recid and cs.speciality_recid = s.recid
group by speciality_name, office_name, street, city, state, zipcode, phone, fax, lastname, firstname, s.recid
order by s.speciality_name, f.office_name, cs.lastname, cs.firstname;
答案 2 :(得分:0)
感谢所有帮助。基本问题归结为:
使用CTE提供解决问题的简单方法。
with t0 as ( -- get all completed records. This table to be used for lookup of consultant_recid.
select s.recid as speciality_recid, f.recid as office_recid, cs.recid as consultant_recid
from speciality s
join office_speciality os on os.speciality_recid = s.recid
join office f on f.recid = os.office_recid
join consultant_office co on co.office_recid = f.recid
join consultant cs on cs.recid = co.consultant_recid and cs.speciality_recid = s.recid
),
t1 as ( -- get speciality and office without duplication.
-- office_speciality is UNIQUE (office_recid, speciality_recid)
select s.recid as speciality_recid, os.office_recid as office_recid
from speciality s
left join office_speciality os on os.speciality_recid = s.recid
group by s.recid, os.office_recid
),
t2 as ( -- add consultants to record when available.
-- left join used to fill in consultant when available, null otherwise.
select t1.speciality_recid, t1.office_recid, t0.consultant_recid
from t1
left join t0 on t0.speciality_recid = t1.speciality_recid and t0.office_recid = t1.office_recid
)
select s.speciality_name, f.office_name, f.street, f.city, f.state, f.zipcode, f.phone, f.fax, cs.lastname, cs.firstname, 0 as status
from t2
join speciality s on s.recid = t2.speciality_recid
join office f on f.recid = t2.office_recid
left join consultant cs on cs.recid = t2.consultant_recid and cs.speciality_recid = s.recid
order by s.speciality_name, f.office_name, cs.lastname;
通过使用左联接来扩展具有信息的记录(如果可用)(否则为null),并且通过防止t1中的重复,所有问题都可以得到简单解决。