使用左联接合并记录会产生太多记录

时间:2018-08-21 21:19:51

标签: sql postgresql

PostgreSQL 10.1

我有下面的SQL命令,它们几乎是 足够好了-但不是完全。 (标题是我能想到的最好的:))

想法是拥有一个可以拥有0,1或更多办事处的专业。每个办事处可以有0,1或更多的顾问(即姓/名)。

目标是始终在每个记录上显示专业名称。 如果该专业有任何办公室,那么该办公室需要(无重复)出现该专业。 (可能会列出一个以上的办公室,但不包括一个专业)。 如果列出的办公室有任何顾问,则应在办公室列出该顾问。 具有顾问的办公室应始终与该顾问一起列出。

根据上述要求,以下SQL本质上会生成太多条记录。也就是说,在研究输出时:

  1. 由于第4行('AAAMMM')已将顾问分配到具有相同专业的同一办公室,而第5行的顾问为空,因此应删除第5行('AAAMMM')。
  2. 第12行和第14行应删除。同样,对于同一办公室的顾问,这两个行都为空,而其上方的相应行确实具有顾问。

如何编写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;

结果表显示为: enter image description here

编辑:使用下面的代码仍然会导致存在完整行时产生过多的部分行。第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;

enter image description here

3 个答案:

答案 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)

感谢所有帮助。基本问题归结为:

  1. 允许使用部分数据,并且应保留部分数据,除非它们是更多信息。 Thas是,如果可以使用某个专业的办公室,则该专业的任何列表都应该有该办公室,并且该专业的空办公室记录也不应列出。在办公室有顾问的情况下,情况也一样。在办公室成立时,不应提供空顾问的记录。
  2. 对最初结果的观察表明,正在生成具有空信息的不必要记录。
  3. 可以有任意数量的专业,每个专业都有办公室,每个办事处都有顾问,而无需重复。

使用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中的重复,所有问题都可以得到简单解决。