如何根据 Oracle 11g+ 中聚合元素的数量改变 LISTAGG() 的结果?
How to vary result of LISTAGG() depending on number of aggregated elements in Oracle 11g+?
如何根据聚合元素的数量在 LISTAGG() 中打印不同的输出?
是否可以在没有额外的 COUNT(*) 查询的情况下获取聚合元素的数量?
有一个示例 DDL:
create table shepherds (
SHEPHERD_ID NUMBER(19),
SHEPHERD_NAME VARCHAR2(50 CHAR)
);
create table sheeps (
SHEEP_ID VARCHAR2(10 CHAR),
SHEEP_NAME VARCHAR2(50 CHAR),
SHEEP_SHEPHERD_ID NUMBER(19)
);
-- insert shepherds
insert into shepherds VALUES (111, 'Asher');
insert into shepherds VALUES (222, 'Joseph');
insert into shepherds VALUES (333, 'Nicodemus');
-- first shepherd (one sheep)
insert into sheeps VALUES ('A', 'Mark', 111);
-- second shepherd (two sheeps)
insert into sheeps VALUES ('A', 'Andres', 222);
insert into sheeps VALUES ('B', 'Jeffrey', 222);
-- third shepherd (three sheeps)
insert into sheeps VALUES ('B', 'Jeffrey', 333);
insert into sheeps VALUES ('A', 'Andres', 333);
insert into sheeps VALUES ('D', 'Andres', 333);
现在我想按以下方式显示所有羊名以换行符分隔的牧羊人:
SELECT
SHEPHERD_NAME,
(SELECT
listagg(SHEEP_ID || ': ' || SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID)
FROM SHEEPS
WHERE SHEEP_SHEPHERD_ID = SHEPHERD_ID)
FROM SHEPHERDS;
结果是:http://sqlfiddle.com/#!4/881a7/3
但是,对于那些只有一只羊的牧羊人,我想把羊的ID字母隐藏起来。
我尝试了以下方法:
SELECT
SHEPHERD_NAME,
(SELECT
listagg(
CASE WHEN COUNT(*) > 1 THEN SHEEP_ID || ': ' ELSE '' END
|| SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID)
FROM SHEEPS
WHERE SHEEP_SHEPHERD_ID = SHEPHERD_ID)
FROM SHEPHERDS;
但是,我收到错误消息:
ORA-00978: nested group function without GROUP BY
http://sqlfiddle.com/#!4/881a7/7
如果只有一个元素要聚合,是否可以 return 来自 LISTAGG() 的不同字符串?
如何在不降低 Oracle 11g 或更高版本中的查询性能的情况下检测聚合元素的数量?
子查询中的条件表达式应该满足您的要求:
SELECT sh.SHEPHERD_NAME,
(SELECT (CASE WHEN COUNT(*) = 1 THEN MAX(s.SHEEP_NAME)
ELSE LISTAGG(s.SHEEP_ID || ': ' || s.SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY s.SHEEP_ID)
END) as SHEEPS
FROM SHEEPS s
WHERE s.SHEEP_SHEPHERD_ID = sh.SHEPHERD_ID
) as SHEEPS
FROM SHEPHERDS sh;
Here 是一个 db<>fiddle.
没有子查询的解决方案使用简单的GROUP BY
、COUNT(*) = 1
来区分羊数和两个不同的LISTAGG
语句
SELECT
s.SHEPHERD_NAME,
case when count(*) = 1 then
listagg(SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID)
else
listagg(SHEEP_ID || ': ' || SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID) end as SHEEPS
FROM SHEPHERDS s
JOIN SHEEPS sh on s.SHEPHERD_ID = sh.SHEEP_SHEPHERD_ID
GROUP BY s.SHEPHERD_NAME /* add SHEPHERD_ID in GROUP BY if the name is not unique */
returns
SHEPHERD_NAME, SHEEPS
Asher Mark
Joseph A: Andres
B: Jeffrey
Nicodemus A: Andres
B: Jeffrey
D: Andres
如何根据聚合元素的数量在 LISTAGG() 中打印不同的输出?
是否可以在没有额外的 COUNT(*) 查询的情况下获取聚合元素的数量?
有一个示例 DDL:
create table shepherds (
SHEPHERD_ID NUMBER(19),
SHEPHERD_NAME VARCHAR2(50 CHAR)
);
create table sheeps (
SHEEP_ID VARCHAR2(10 CHAR),
SHEEP_NAME VARCHAR2(50 CHAR),
SHEEP_SHEPHERD_ID NUMBER(19)
);
-- insert shepherds
insert into shepherds VALUES (111, 'Asher');
insert into shepherds VALUES (222, 'Joseph');
insert into shepherds VALUES (333, 'Nicodemus');
-- first shepherd (one sheep)
insert into sheeps VALUES ('A', 'Mark', 111);
-- second shepherd (two sheeps)
insert into sheeps VALUES ('A', 'Andres', 222);
insert into sheeps VALUES ('B', 'Jeffrey', 222);
-- third shepherd (three sheeps)
insert into sheeps VALUES ('B', 'Jeffrey', 333);
insert into sheeps VALUES ('A', 'Andres', 333);
insert into sheeps VALUES ('D', 'Andres', 333);
现在我想按以下方式显示所有羊名以换行符分隔的牧羊人:
SELECT
SHEPHERD_NAME,
(SELECT
listagg(SHEEP_ID || ': ' || SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID)
FROM SHEEPS
WHERE SHEEP_SHEPHERD_ID = SHEPHERD_ID)
FROM SHEPHERDS;
结果是:http://sqlfiddle.com/#!4/881a7/3
但是,对于那些只有一只羊的牧羊人,我想把羊的ID字母隐藏起来。
我尝试了以下方法:
SELECT
SHEPHERD_NAME,
(SELECT
listagg(
CASE WHEN COUNT(*) > 1 THEN SHEEP_ID || ': ' ELSE '' END
|| SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID)
FROM SHEEPS
WHERE SHEEP_SHEPHERD_ID = SHEPHERD_ID)
FROM SHEPHERDS;
但是,我收到错误消息:
ORA-00978: nested group function without GROUP BY
http://sqlfiddle.com/#!4/881a7/7
如果只有一个元素要聚合,是否可以 return 来自 LISTAGG() 的不同字符串?
如何在不降低 Oracle 11g 或更高版本中的查询性能的情况下检测聚合元素的数量?
子查询中的条件表达式应该满足您的要求:
SELECT sh.SHEPHERD_NAME,
(SELECT (CASE WHEN COUNT(*) = 1 THEN MAX(s.SHEEP_NAME)
ELSE LISTAGG(s.SHEEP_ID || ': ' || s.SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY s.SHEEP_ID)
END) as SHEEPS
FROM SHEEPS s
WHERE s.SHEEP_SHEPHERD_ID = sh.SHEPHERD_ID
) as SHEEPS
FROM SHEPHERDS sh;
Here 是一个 db<>fiddle.
没有子查询的解决方案使用简单的GROUP BY
、COUNT(*) = 1
来区分羊数和两个不同的LISTAGG
语句
SELECT
s.SHEPHERD_NAME,
case when count(*) = 1 then
listagg(SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID)
else
listagg(SHEEP_ID || ': ' || SHEEP_NAME, CHR(10)) WITHIN GROUP (ORDER BY SHEEP_ID) end as SHEEPS
FROM SHEPHERDS s
JOIN SHEEPS sh on s.SHEPHERD_ID = sh.SHEEP_SHEPHERD_ID
GROUP BY s.SHEPHERD_NAME /* add SHEPHERD_ID in GROUP BY if the name is not unique */
returns
SHEPHERD_NAME, SHEEPS
Asher Mark
Joseph A: Andres
B: Jeffrey
Nicodemus A: Andres
B: Jeffrey
D: Andres