GBase 8a
适配迁移
文章
南大通用GBase 8a 语法改造oracle12c字符串聚合函数LISTAGG WITHIN GROUP方法说明
发表于2026-02-03 13:36:35292次浏览9个评论
问题描述
在oracle迁移至8a数据库时,遇到以下SQL语法,不能直接迁移:
SELECT T.DATA_DATE,
T.CONT_NO,
SUBSTR(LISTAGG(TO_CHAR(T.NVOICE_NO), ';' ON OVERFLOW TRUNCATE '...' WITH COUNT) WITHIN GROUP(ORDER BY T.NVOICE_NO),1,200) AS NVOICE_NO,
T.INVOICE_TYPE,
SUM(T.NVOICE_AMT)
FROM ODS_IQP_NVOICE T
WHERE T.DATA_DATE = CURDAY
GROUP BY T.DATA_DATE, T.CONT_NO, T.INVOICE_TYPE;改造方式
1. 开始尝试这种方式改造:
SELECT
T.DATA_DATE,
T.CONT_NO,
CASE
WHEN CHAR_LENGTH(T.NVOICE_NO_LIST) <= 200 THEN
T.NVOICE_NO_LIST
ELSE
CONCAT(
SUBSTRING(T.NVOICE_NO_LIST, 1, 196),
'...(',
CAST((T.TOTAL_COUNT - (
LENGTH(SUBSTRING(T.NVOICE_NO_LIST, 1, 196)) -
LENGTH(REPLACE(SUBSTRING(T.NVOICE_NO_LIST, 1, 196), ';', ''))
) - 1) AS CHAR),
')'
)
END AS NVOICE_NO,
T.INVOICE_TYPE,
T.NVOICE_AMT_SUM
FROM (
SELECT
DATA_DATE,
CONT_NO,
INVOICE_TYPE,
GROUP_CONCAT(NVOICE_NO ORDER BY NVOICE_NO SEPARATOR ';') AS NVOICE_NO_LIST,
SUM(NVOICE_AMT) AS NVOICE_AMT_SUM,
COUNT(*) AS TOTAL_COUNT
FROM ODS_IQP_NVOICE
WHERE DATA_DATE = CURDATE()
GROUP BY DATA_DATE, CONT_NO, INVOICE_TYPE
) T;
但该方式容易存在GROUP_CONCAT聚合后内存越界的问题。
2. 后尝试通过以下方式改造:
SELECT T.DATA_DATE,
T.CONT_NO,
GROUP_CONCAT(T.NVOICE_NO ORDER BY T.NVOICE_NO topN 200 SEPARATOR ';' ) AS NVOICE_NO,
T.INVOICE_TYPE,
SUM(T.NVOICE_AMT) AS NVOICE_AMT_SUM
FROM ODS_IQP_NVOICE T
WHERE T.DATA_DATE = CURDATE()
GROUP BY T.DATA_DATE, T.CONT_NO, T.INVOICE_TYPE;
即,取分组内前200的方式
原理说明
(1)sql要实现什么功能
TO_CHAR(T.NVOICE_NO)
将发票号字段NVOICE_NO转换为字符类型(避免拼接时类型异常)
LISTAGG(..., ';') WITHIN GROUP(ORDER BY T.NVOICE_NO)
按T.NVOICE_NO排序后,将同组的发票号用;拼接。核心是 “分组内字符串拼接 ”
ON OVERFLOW TRUNCATE '...' WITH COUNT
LISTAGG 的溢出处理参数:
ON OVERFLOW TRUNCATE:当拼接结果超长时截断
'...':截断后追加的标识字符
WITH COUNT:在截断后补充 “(剩余 N 个)” 的计数提示SUBSTR(...,1,200)最终将拼接结果截取前 200 个字符(双重保险,防止溢出)
(2)改造关键逻辑说明
核心函数替换:
Oracle
LISTAGG(字段, ';') WITHIN GROUP(ORDER BY 字段)→ GBase8a语法GROUP_CONCAT(字段 ORDER BY 字段 SEPARATOR ';')Oracle
CURDAY→ GBase8aCURDATE()(注意:Oracle 的CURDAY如果是自定义变量 / 函数,需对应调整)
溢出截断模拟:
用
CHAR_LENGTH判断拼接后总长度是否超过 200(CHAR_LENGTH计算字符数,LENGTH计算字节数,根据编码选择)若超长:截取前 196 个字符,拼接
...(剩余数量),保证最终长度≤200剩余数量计算逻辑:总条数 - 截断后包含的条数(通过 “总长度 - 去分隔符后长度” 得到分隔符数量,分隔符数量 + 1 = 已包含条数)
评论
登录后才可以发表评论
山佳发表于 6个月前
学习了
枫溪发表于 6个月前
1
枫溪发表于 6个月前
2
枫溪发表于 6个月前
3
枫溪发表于 6个月前
4
枫溪发表于 6个月前
5
郝老师发表于 6个月前
国产数据集替代的实用方案
BYRAN发表于 3个月前
该函数在9.5.3.28.13 版本中,增加了对 STRING_AGG 函数进行替代。 建议使用产品中该函数。
BYRAN发表于 3个月前
使用方式说明如下:
STRING_AGG(expression [separator delimiter]) within(order by col_name[asc/desc])
功能:配合group by聚合函数使用,将指定字符串内容以指定分隔符拼接在一起。功能同group_concat。
参数说明:
express 字符串类型的表达式,比如列字符串
separator delimiter 可选参数,用于指定分隔符,separator是关键字。如果未指定该参数,默认使用逗号作为分隔符。
within (order by col_name[asc/desc]) 用于指定排序列。
示例:
select id,string_agg(name separator '++') within(order by id) as test from t1 group by id;
功能限制说明如下:
1)函数支持数据类型理论上无限制边界,默认的系统参数group_concat_max_len为1024,部分用例会报越界,需要设置group_concat_max_len的范围大一些,用例执行成功
示例:set global group_concat_max_len =10240;
2)暂不支持blob,longblob数据类型
STRING_AGG(expression [separator delimiter]) within(order by col_name[asc/desc])
功能:配合group by聚合函数使用,将指定字符串内容以指定分隔符拼接在一起。功能同group_concat。
参数说明:
express 字符串类型的表达式,比如列字符串
separator delimiter 可选参数,用于指定分隔符,separator是关键字。如果未指定该参数,默认使用逗号作为分隔符。
within (order by col_name[asc/desc]) 用于指定排序列。
示例:
select id,string_agg(name separator '++') within(order by id) as test from t1 group by id;
功能限制说明如下:
1)函数支持数据类型理论上无限制边界,默认的系统参数group_concat_max_len为1024,部分用例会报越界,需要设置group_concat_max_len的范围大一些,用例执行成功
示例:set global group_concat_max_len =10240;
2)暂不支持blob,longblob数据类型
热门帖子
- 12025-12-01浏览数:182764
- 22023-05-09浏览数:25062
- 42023-09-25浏览数:18526
- 52020-05-11浏览数:17529