博主介绍:✌全网粉丝24W+,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌
技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物联网、机器学习等设计与开发。
感兴趣的可以先关注收藏起来,在工作中、生活上等遇到相关问题都可以给我留言咨询,希望帮助更多的人。
技术扩展 :最近发现了一个特别好用的人工智能学习网站,通俗易懂,风趣幽默,忍不住想分享一下给大家,进入传送门:https://www.captainbed.cn/no8g/。
人大金仓数据库V9函数 sys.concat不存在的问题解决方案
- 一、现象描述
- 二、问题原因
-
- [2.1 人大金仓 9 对`concat`函数参数类型校验更严格](#2.1 人大金仓 9 对
concat函数参数类型校验更严格) - [2.2 原生 `concat` 仅支持两个入参](#2.2 原生
concat仅支持两个入参) - [2.3 数据库模式为兼容oracle数据库](#2.3 数据库模式为兼容oracle数据库)
- [2.1 人大金仓 9 对`concat`函数参数类型校验更严格](#2.1 人大金仓 9 对
- 三、解决方案
-
- [3.1 方案一:使用 `||` 字符串拼接符(金仓 / PostgreSQL 原生推荐)](#3.1 方案一:使用
||字符串拼接符(金仓 / PostgreSQL 原生推荐)) - [3.2 方案二:全局兼容(自定义 concat 函数,不推荐临时查询用)](#3.2 方案二:全局兼容(自定义 concat 函数,不推荐临时查询用))
- [3.1 方案一:使用 `||` 字符串拼接符(金仓 / PostgreSQL 原生推荐)](#3.1 方案一:使用
- 四、补充说明
首先确定的一点是人大金仓V9版本中是有 concat() 函数的。只不过是金仓 9 的 concat() 不支持多参数拼接 (仅支持 2 个参数),这是根源,单纯转类型没用。
一、现象描述
开发环境部署的是人大金仓V8版本数据库,测试环境是人大金仓V9版本的数据库。在执行以下 SQL 时开发环境的V8数据库能正常执行,而到了测试环境的V9版本的数据库时居然报错。
sql
SELECT
fa.*,
traintypedic.dict_label AS train_type_name,
hi.thread_slug,
faultHandledic.dict_label AS fault_state_name,
bdi.driver_name AS driver_name,
fard.*,
concat ( train_type_name, '-', fa.train_no, '-', fa.train_port ) AS train_no_ext,
concat ( train_type_name, '-', fa.train_no, '-', fa.train_port ) AS vr_name,
concat ( train_type_name, '-', fa.train_no, '-', fa.train_port ) AS model_name
FROM
faultalarm fa
LEFT JOIN faultalarm_rundetail fard ON fa.ID = fard.alarm_id
LEFT JOIN base_driverinfo bdi ON fa.driver_code = bdi.driver_code
LEFT JOIN sys_dict_data traintypedic ON traintypedic.dict_value = fa.train_type
AND traintypedic.dict_type = 'train_type'
LEFT JOIN sys_dict_data faultHandledic ON faultHandledic.dict_value = fa.fault_state
AND faultHandledic.dict_type = 'fault_handle_state'
LEFT JOIN handinfo hi ON hi.ID = fa.handinfo_id
ORDER BY
fa.fault_time DESC
报错详情如下:
bash
11:37:56.748 [http-nio-28088-exec-21] ERROR c.l.f.w.e.GlobalExceptionHandler - [handleRuntimeException,119] - 请求地址'/fh/handinfo/realTimeDataByTrainNum/E',发生未知异常.
org.springframework.jdbc.BadSqlGrammarException:
### Error querying database. Cause: com.kingbase8.util.KSQLException: ERROR: 函数 sys.concat(varchar, unknown, varchar, unknown, varchar) 不存在
Hint: 没有匹配指定名称和参数类型的函数. 您也许需要增加明确的类型转换.
Position: 578 At Line: 7, Line Position: 16
### The error may exist in URL [jar:nested:/home/leg/leg-server/lib/leg-admin-V1.0.0.2.jar/!BOOT-INF/lib/leg-service-1.0.0.jar!/mapper/FhFaultalarmMapper.xml]
### The error may involve com.leg.service.mapper.FhFaultalarmMapper.selectFhFaultalarmList-Inline
### The error occurred while setting parameters
### SQL: select fa.id, fa.fault_code, fa.fault_content, fa.fault_time, fa.train_type, fa.train_no, fa.train_port, fa.train_num, fa.train_id, fa.driver_code, fa.fault_state, fa.create_time, fa.handinfo_id, traintypedic.dict_label as train_type_name, hi.thread_slug, faultHandledic.dict_label as fault_state_name, bdi.driver_name as driver_name, fard.train_speed, fard.run_route, fard.run_line, fard.run_dir, fard.run_mileage, fard.ahead_signal, fard.ahead_station, fard.ahead_phasesplit_distance, concat(train_type_name, '-', fa.train_no, '-', fa.train_port) as train_no_ext, concat(train_type_name, '-', fa.train_no, '-', fa.train_port) as vr_name, concat(train_type_name, '-', fa.train_no, '-', fa.train_port) as model_name from fh_faultalarm fa left join fh_faultalarm_rundetail fard on fa.id = fard.alarm_id left join base_driverinfo bdi on fa.driver_code = bdi.driver_code left join sys_dict_data traintypedic on traintypedic.dict_value=fa.train_type and traintypedic.dict_type='train_type' left join sys_dict_data faultHandledic on faultHandledic.dict_value=fa.fault_state and faultHandledic.dict_type='fault_handle_state' left join fh_handinfo hi on hi.id = fa.handinfo_id WHERE fa.fault_time >= ? AND fa.fault_time <= ? order by fa.fault_time desc
### Cause: com.kingbase8.util.KSQLException: ERROR: 函数 sys.concat(varchar, unknown, varchar, unknown, varchar) 不存在
Hint: 没有匹配指定名称和参数类型的函数. 您也许需要增加明确的类型转换.
Position: 578 At Line: 7, Line Position: 16
; bad SQL grammar []
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:112)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:107)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:116)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:116)
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:439)
at jdk.proxy2/jdk.proxy2.$Proxy94.selectList(Unknown Source)
二、问题原因
2.1 人大金仓 9 对concat函数参数类型校验更严格
人大金仓 9 对concat函数参数类型校验更严格 ,'-'字面量被识别为unknown类型,和字段varchar类型混用时,无法匹配内置concat函数,金仓 8 兼容宽松所以正常执行。
2.2 原生 concat 仅支持两个入参
人大金仓 9 内核限制:原生 concat 仅支持两个入参,不支持多参数,所以 5 个参数直接报错。
2.3 数据库模式为兼容oracle数据库
sql
# 可以查看数据库的兼容模式,使用以下 sql 语句
SHOW database_mode;
# 此处应该会显示 oracle,兼容oracle模式下也会导致上面报错。
人大金仓V9版本想安装成适配pg 版本的,结果安装后使用 show database_mode 语句查询出来的是 oracle,怎么办呢?别担心,安装完成后发现模式不对,这个问题完全可以解决,而且不用重装整个软件。如果想变更模式,可以参考我写的另一篇文章。
我将数据库模式从 oracle 修改为 pg 之后就不再报上面的错误了。
三、解决方案
3.1 方案一:使用 || 字符串拼接符(金仓 / PostgreSQL 原生推荐)
金仓完全兼容 || 拼接,无需类型转换,语法更简洁:
sql
train_type_name || '-' || fa.train_no || '-' || fa.train_port AS train_no_ext,
train_type_name || '-' || fa.train_no || '-' || fa.train_port AS vr_name,
train_type_name || '-' || fa.train_no || '-' || fa.train_port AS model_name
完整 SQL 替换对应行即可。
即完整的SQL如下:
sql
SELECT
fa.*,
traintypedic.dict_label AS train_type_name,
hi.thread_slug,
faultHandledic.dict_label AS fault_state_name,
bdi.driver_name AS driver_name,
fard.train_speed,
fard.run_route,
fard.run_line,
fard.run_dir,
fard.run_mileage,
fard.ahead_signal,
fard.ahead_station,
fard.ahead_phasesplit_distance,
train_type_name || '-' || fa.train_no || '-' || fa.train_port AS train_no_ext,
train_type_name || '-' || fa.train_no || '-' || fa.train_port AS vr_name,
train_type_name || '-' || fa.train_no || '-' || fa.train_port AS model_name
FROM
faultalarm fa
LEFT JOIN faultalarm_rundetail fard ON fa.ID = fard.alarm_id
LEFT JOIN base_driverinfo bdi ON fa.driver_code = bdi.driver_code
LEFT JOIN sys_dict_data traintypedic ON traintypedic.dict_value = fa.train_type
AND traintypedic.dict_type = 'train_type'
LEFT JOIN sys_dict_data faultHandledic ON faultHandledic.dict_value = fa.fault_state
AND faultHandledic.dict_type = 'fault_handle_state'
LEFT JOIN handinfo hi ON hi.ID = fa.handinfo_id
ORDER BY
fa.fault_time DESC;
3.2 方案二:全局兼容(自定义 concat 函数,不推荐临时查询用)
如果大量老 SQL 都有该问题,可创建兼容函数(仅执行一次):
sql
CREATE OR REPLACE FUNCTION sys.concat(VARIADIC args anyarray)
RETURNS text AS $$
BEGIN
RETURN array_to_string(args, '');
END;
$$ LANGUAGE plpgsql IMMUTABLE;
注意:该方案影响全库,优先用方案 1。
四、补充说明
- 人大金仓 9 基于 PostgreSQL 高版本内核,类型推断更严谨,这是和 V8 的核心差异;
- 业务 SQL 优先使用
||做字符串拼接,是 PG 系数据库标准写法,跨版本最稳定; - 三条拼接内容完全一致,也可以用子查询 / CTE 只计算一次,优化性能。
好了,今天分享到这里。希望你喜欢这次的探索之旅!不要忘记 "点赞" 和 "关注" 哦,我们下次见!🎈
本文完结!
祝各位大佬和小伙伴身体健康,万事如意,发财暴富,扫下方二维码与我一起交流!!!