Oracle 将两行合并为具有更多列的单行

Oracle merge two rows as single row with more columns

我有两个表 Employee,Employeerows。我必须提取具有角色 2 或 3 的员工记录。 我有以下查询。

SELECT
    E.ID,
    E.NAME,
    ER.PHONE,
    ER.ADDRESS,
    ER.ROLE
    
FROM
 EMPLOYEE E LEFT JOIN EMPLOYEEROWS ER ON E.ID = ER.ID WHERE ER.ROLE_ID IN (2,3)

每个员工 returns 1 或 2 条记录

ID      NAME        PHONE       ADDRESS     ROLE
1       ABC         9898989     ABC NJ       2
1       ABC         7878787     ABC XJ       3
2       DEF         7898765     DEF NJ       2

但是如果该员工有 2 条记录,我必须将 phone 编号和地址作为单独列的该员工的两条记录合并为一条。 我的结果应该是这样的。

ID      NAME        PHONE       ALT_PHONE     ADDRESS      ALT_ADDESS   
1       ABC         9898989     7878787        ABC NJ       ABC XJ          
2       DEF         7898765                    DEF NJ

请帮我解决这个问题。

您可以使用条件聚合进行透视:

select e.id, e.name,
    max(case when er.role_id = 2 then er.phone   end) as phone,
    max(case when er.role_id = 3 then er.phone   end) as alt_phone,
    max(case when er.role_id = 2 then er.address end) as address,
    max(case when er.role_id = 3 then er.address end) as alt_address
from employee e 
left join employeerows er on e.id = er.id where er.role_id in (2,3)
group by e.id, e.name

您可以使用条件聚合。但是您的查询 没有执行 LEFT OUTER JOIN 但它是 INNER JOIN 因为您在 WHERE 子句中使用了 er.role_id in (2,3)

使用以下聚合技术获取所需结果:

SELECT
    E.ID,
    E.NAME,
    MIN(ER.PHONE),
    CASE WHEN MIN(ER.PHONE) <> MAX(ER.PHONE) THEN MAX(ER.PHONE) END AS ALT_PHONE,
    MIN(ER.ADDRESS),
    CASE WHEN MIN(ER.ADDRESS) <> MAX(ER.ADDRESS) THEN MAX(ER.ADDRESS) END AS ALT_ADDRESS
FROM EMPLOYEE E 
LEFT JOIN EMPLOYEEROWS ER ON E.ID = ER.ID 
                   AND ER.ROLE_ID IN (2,3) -- added it in the join condition
GROUP BY E.ID, E.NAME;

您可以使用条件聚合。但是 left join 似乎是多余的。如果您想要没有行的“员工”,您只想使用 left join

根据您的数据,“2”对应主地址,“3”对应备用地址:

select e.id, e.name,
       max(case when er.role_id = 2 then er.phone end) as phone,
       max(case when er.role_id = 3 then er.phone end) as alt_phone,
       max(case when er.role_id = 2 then er.address end) as address,
       max(case when er.role_id = 3 then er.address end) as alt_address
from employee e join
     employeerows er
     on e.id = er.id
where er.role_id in (2, 3)
group by e.id, e.name;

但是,如果可能缺少“2”,那么您可以将其表述为:

select e.id, e.name,
       max(case when seqnum = 2 then er.phone end) as phone,
       max(case when seqnum = 3 then er.phone end) as alt_phone,
       max(case when seqnum = 2 then er.address end) as address,
       max(case when seqnum = 3 then er.address end) as alt_address
from employee e join
     (select er.*,
             row_number() over (partition by er.id order by er.role_id) as seqnum
      from employeerows er
      where er.role_id in (2, 3)
     ) er
     on e.id = er.id
group by e.id, e.name;