问题: ORA-01489: result of string concatenation is too long
1. 查看Oracle数据库版本
如果数据库版本为18c或更高版本,则可以使用json_arrayagg替代xmlagg
SELECT * FROM V$VERSION;
2. 由于Oracle数据库版本是19c,所以使用JSON_ARRAYAGG
2.1 数据准备
创建students表,为后续演示JSON_ARRAYAGG功能做准备
DROP TABLE students;
COMMIT;
CREATE TABLE students
( student_id NUMBER(6)
, first_name VARCHAR2(20)
, last_name VARCHAR2(25)
, email VARCHAR2(40)
, phone_number VARCHAR2(20)
, join_date DATE
, class_id VARCHAR2(20)
, fees NUMBER(8,2)
, professor_id NUMBER(6)
, department_id NUMBER(4)
) ;
CREATE UNIQUE INDEX stu_id_pk ON students (student_id) ;
INSERT INTO students VALUES (100,'SMITH','JAMES','SMITH.JAMES@notreal.com','111.111.1245',TO_DATE('17-06-2003','DD-MM-YYYY'),'INS_CHAIRMAN',24000,NULL,NULL);
INSERT INTO students VALUES (101,'JOHNSON','JOHN','JOHNSON.JOHN@notreal.com','111.111.1246',TO_DATE('21-09-2005','DD-MM-YYYY'),'INS_VP',17000,100,90);
INSERT INTO students VALUES (102,'WILLIAMS','ROBERT','WILLIAMS.ROBERT@notreal.com','111.111.1247',TO_DATE('13-01-2001','DD-MM-YYYY'),'INS_VP',17000,100,90);
INSERT INTO students VALUES (103,'BROWN','MICHAEL','BROWN.MICHAEL@notreal.com','111.111.1248',TO_DATE('03-01-2006','DD-MM-YYYY'),'INS_STAFF',9000,102,60);
INSERT INTO students VALUES (104,'JONES','WILLIAM','JONES.WILLIAM@notreal.com','111.111.1249',TO_DATE('21-05-2007','DD-MM-YYYY'),'INS_STAFF',6000,103,60);
INSERT INTO students VALUES (105,'MILLER','DAVID','MILLER.DAVID@notreal.com','111.111.1250',TO_DATE('25-06-2005','DD-MM-YYYY'),'INS_STAFF',4800,103,60);
INSERT INTO students VALUES (106,'DAVIS','RICHARD','DAVIS.RICHARD@notreal.com','111.111.1251',TO_DATE('05-02-2006','DD-MM-YYYY'),'INS_STAFF',4800,103,60);
INSERT INTO students VALUES (107,'GARCIA','CHARLES','GARCIA.CHARLES@notreal.com','111.111.1252',TO_DATE('07-02-2007','DD-MM-YYYY'),'INS_STAFF',4200,103,60);
INSERT INTO students VALUES (108,'RODRIGUEZ','JOSEPH','RODRIGUEZ.JOSEPH@notreal.com','111.111.1253',TO_DATE('17-08-2002','DD-MM-YYYY'),'CL_PHY',12008,101,100);
INSERT INTO students VALUES (109,'WILSON','THOMAS','WILSON.THOMAS@notreal.com','111.111.1254',TO_DATE('16-08-2002','DD-MM-YYYY'),'CL_MATH',9000,108,100);
INSERT INTO students VALUES (110,'MARTINEZ','CHRISTOPHER','MARTINEZ.CHRISTOPHER@notreal.com','111.111.1255',TO_DATE('28-09-2005','DD-MM-YYYY'),'CL_MATH',8200,108,100);
INSERT INTO students VALUES (111,'ANDERSON','DANIEL','ANDERSON.DANIEL@notreal.com','111.111.1256',TO_DATE('30-09-2005','DD-MM-YYYY'),'CL_MATH',7700,108,100);
INSERT INTO students VALUES (112,'TAYLOR','PAUL','TAYLOR.PAUL@notreal.com','111.111.1257',TO_DATE('07-03-2006','DD-MM-YYYY'),'CL_MATH',7800,108,100);
INSERT INTO students VALUES (113,'THOMAS','MARK','THOMAS.MARK@notreal.com','111.111.1258',TO_DATE('07-12-2007','DD-MM-YYYY'),'CL_MATH',6900,108,100);
COMMIT;
2.2 利用JSON_ARRAYAGG进行拼接字符串
SELECT class_id,
replace(JSON_ARRAYAGG(first_name || ' ' || last_name ORDER BY class_id RETURNING CLOB),'"','') AS retunring_val
FROM students
GROUP BY class_id;
-------------------------------------------------
输出结果:
CL_MATH [WILSON THOMAS,THOMAS MARK,TAYLOR PAUL,ANDERSON DANIEL,MARTINEZ CHRISTOPHER]
CL_PHY [RODRIGUEZ JOSEPH]
INS_CHAIRMAN [SMITH JAMES]
INS_STAFF [BROWN MICHAEL,GARCIA CHARLES,DAVIS RICHARD,MILLER DAVID,JONES WILLIAM]
INS_VP [JOHNSON JOHN,WILLIAMS ROBERT]
这里SQL展示了JSON_ARRAYAGG的基本用法,即将first_name与last_name进行拼接,其他详细配置请参考SQL聚合函数 JSON_ARRAYAGG
注:CLOB 是内置类型,它将字符大对象 (Character Large Object) 存储为数据库表某一行中的一个列值.
3. 对JSON_ARRAYAGG查询结果进行处理
3.1 利用TRIM()去除首尾部的[]并替换’,‘为’;’
WITH TEMP AS (SELECT CLASS_ID,
TRIM(REPLACE(JSON_ARRAYAGG(FIRST_NAME || ' ' || LAST_NAME ORDER BY CLASS_ID RETURNING CLOB), '"',
'')) AS RETUNRING_VAL
FROM STUDENTS
GROUP BY CLASS_ID)
SELECT REPLACE(TRIM(TRAILING ']' FROM
TRIM(LEADING '[' FROM RETUNRING_VAL)), ',', ';') AS RETUNRING_VAL
FROM TEMP;
4.解决问题时遇到的小知识点
4.1 listagg()列转行函数如果长度超过4000,会报Error,解决方法是LISTAGG(CAST(NAME AS VARCHAR(10000)), ‘,’)
4.2 Trim()参数
- LEADING 开头字符
- TRAILING 结尾字符
- BOTH 开头和结尾字符
4.3 CAST可以将一种类型转换为另外一种类型
SELECT CAST('123.4567' AS NUMBER(10,2)) AS NUM FROM DUAL;