【问题标题】:Oracle merge two rows as single row with more columnsOracle将两行合并为具有更多列的单行
【发布时间】:2021-03-31 03:36:58
【问题描述】:

我有两个表 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)

这将为每个员工返回 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 条记录,我必须将该员工的两条记录合并为一条,并将电话号码和地址作为单独的列。 我的结果应该是这样的。

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

请帮帮我。

【问题讨论】:

    标签: sql oracle pivot aggregate-functions


    【解决方案1】:

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

    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
    

    【讨论】:

      【解决方案2】:

      您可以使用条件聚合。但是您的查询没有执行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;
      

      【讨论】:

        【解决方案3】:

        您可以使用条件聚合。但是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;
        

        【讨论】:

          猜你喜欢
          • 2019-02-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-04
          • 2018-08-14
          相关资源
          最近更新 更多