如何使用LISTAGG和多列在SQL(oracle)中合并多行?

时间:2018-08-08 14:59:20

标签: sql oracle

我有一条SQL语句返回的数据如下:

SOURCEDID   ORGSOURCEDIDS   ROLE    USERNAME    EMAIL   GIVENNAME   FAMILYNAME
123456  0   teacher test.teacher@   test.teacher@   Test    Teacher
123456  1802    teacher test.teacher@test.teacher@  Test    Teacher
123456  1803    teacher test.teacher@   test.teacher@   Test    Teacher
123456  1804    teacher test.teacher@   test.teacher@   Test    Teacher

我试图在逗号分隔的列表中将具有相同“ SOURCEDID”的行与“ ORGSOURCEDIDS”合并为一行,例如:“ 0,1802,1803,1804”。除ORGSOURCEDIDS之外的所有其他数据都始终相同(当您编辑任何一条记录时,系统会在每个组织中创建和更新单独的记录)。

我正在尝试使用以下SQL:

SELECT TO_CHAR(TEACHERNUMBER) as sourcedId, 
   LISTAGG(schoolid, ',') WITHIN GROUP (ORDER BY schoolid) orgSourcedIds
FROM teachers 
group by TEACHERNUMBER

哪个确实给了我这样的东西:

SOURCEDID   ORGSOURCEDIDS
123456  0,1802,1803,1804

但是我无法从上面的示例中找出如何在其他未更改的列中重新添加(角色,用户名,电子邮件,给定名称,姓氏)。如果我尝试添加其他列,则会得到“不是GROUP BY表达式”。

我也尝试过这样的事情:

SELECT TO_CHAR(TEACHERNUMBER) as sourcedId, 
   LISTAGG(schoolid, ',') WITHIN GROUP (ORDER BY schoolid) orgSourcedIds,
   LISTAGG(EMAIL_ADDR, ',') WITHIN GROUP (ORDER BY EMAIL_ADDR) EMAIL_ADDR
FROM teachers 
group by TEACHERNUMBER
order by TEACHERNUMBER;

返回如下内容:

SOURCEDID   ORGSOURCEDIDS   EMAIL_ADDR
123456  0,1802,1803,1804    test.teacher@,test.teacher@,test.teacher@,test.teacher@

但是在我的情况下,具有相同SOURCEDID的每一行的EMAIL_ADDR将始终相同,因此在该字段上使用LISTAGG没有帮助。

2 个答案:

答案 0 :(得分:1)

只需将它们添加到selectgroup by

SELECT TO_CHAR(TEACHERNUMBER) as sourcedId, 
       LISTAGG(schoolid, ',') WITHIN GROUP (ORDER BY schoolid) as orgSourcedIds,
       ROLE, USERNAME, EMAIL, GIVENNAME, FAMILYNAME
FROM teachers 
GROUP BY TEACHERNUMBER, ROLE, USERNAME, EMAIL, GIVENNAME, FAMILYNAME

答案 1 :(得分:0)

Listagg是一个聚合函数,因此对于其余的列,您必须 1)将它们移动到group by子句中,如@GordonLinoff或 2所建议的那样)使用任何聚合函数,例如max() 3)检查它们是否重复以及是否重复-使用listagg(),否-使用{{1} }:

max()

结果:

-- sample data
with t(sourcedid, orgsourcedids, role, email) as (
    select 123456,    0, 'teacher1', 'test@teachers.org' from dual union all
    select 123456, 1802, 'teacher2', 'test@teachers.org' from dual union all
    select 123456, 1803, 'teacher1', 'test@teachers.org' from dual union all
    select 123456, 1804, 'teacher1', 'test@teachers.org' from dual )
-- end of sample data
select sourcedid, 
       listagg(orgsourcedids, ', ') within group (order by orgsourcedids) orgs, 
       case when count(distinct role) > 1 
            then listagg(role, ', ') within group (order by orgsourcedids) 
            else max(role) end roles,
       case when count(distinct email) > 1 
            then listagg(email, ', ') within group (order by orgsourcedids) 
            else max(email) end emails       
  from t
  group by sourcedid

角色不同,因此它们以列表的形式显示,电子邮件很常见,因此只有一个。