【达梦数据库】函数传参问题复现
在处理问题的过程中,客户反馈在当前版本下函数参数名和函数中引用表的列名相同的话,会报错,请求我们确认是否为BUG。复现过程如下:
1、创建基础表数据
--版本:8.1.3.100:
--创建表kcrp_dict_trans
CREATE TABLE kcrp_dict_trans(
item_value VARCHAR(255),
src_sys_no VARCHAR(255),
dict_type VARCHAR(255),
dict_id VARCHAR(255)
);
--插入数据
insert into "kcrp_dict_trans"(item_value,src_sys_no,dict_type,dict_id)
values('abc',1,2,3);
insert into "kcrp_dict_trans"(item_value,src_sys_no,dict_type,dict_id)
values('def',4,5,6);
--提交
COMMIT;
--查询
select * from "kcrp_dict_trans";
2、函数参数名和引用的表的字段名相同
------------创建函数1:函数参数名和引用的表的字段名相同------------
CREATE OR REPLACE FUNCTION dict_kcrp(
src_sys_no IN VARCHAR,
dict_type IN VARCHAR,
dict_id IN VARCHAR
) RETURN VARCHAR
AS
-- 声明密码变量,指定长度
v_pass VARCHAR(255);
BEGIN
v_pass := '';
SELECT item_value INTO v_pass
FROM kcrp_dict_trans A
WHERE A.src_sys_no = src_sys_no
AND A.dict_type = dict_type
AND A.dict_id = dict_id;
-- 返回查询到的密码
RETURN v_pass;
END;
------------查询函数1------------
select "dict_kcrp"(1,2,3) from DUAL;
--结果
报错
select "dict_kcrp"(1,2,3) from dual;
执行失败(语句1)
-7046: SELECT INTO中包含多行数据
-7046: dict_kcrp line 16
3、函数参数名和引用的表的字段名不同
------------------------------------------------
------------创建函数2:函数参数名和引用的表的字段名不相同------------
CREATE OR REPLACE FUNCTION dict_kcrp1(
p_src_sys_no IN VARCHAR,
p_dict_type IN VARCHAR,
p_dict_id IN VARCHAR
) RETURN VARCHAR
AS
-- 声明密码变量,指定长度
v_pass VARCHAR(255);
BEGIN
v_pass := '';
SELECT item_value INTO v_pass
FROM kcrp_dict_trans A
WHERE A.src_sys_no = p_src_sys_no
AND A.dict_type = p_dict_type
AND A.dict_id = p_dict_id;
-- 返回查询到的密码
RETURN v_pass;
END;
------------查询函数2------------
SELECT "dict_kcrp1"(1,2,3)from DUAL;
--结果:abc
SELECT "dict_kcrp1"(4,5,6)from DUAL;
--结果:def
4、其他版本
--复现140版本,出现同样的问题:--03134284172-20240527-229704-20093 Pack5
--复现162版本,出现同样的问题:--03134284172-20240527-229704-20093 Pack5
--oracle上复现,出现同样的问题
5、结论:
--为了更加明确和避免潜在的命名冲突,建议区分参数和列名规避--
CREATE OR REPLACE FUNCTION dict_kcrp(
p_src_sys_no IN VARCHAR, -- 使用前缀 p_ 来区分参数和列名
p_dict_type IN VARCHAR, -- 同上
p_dict_id IN VARCHAR -- 同上
) RETURN VARCHAR
AS
-- 声明密码变量,指定长度
v_pass VARCHAR(255);
BEGIN
-- 初始化变量为 NULL 或空字符串(在这个场景下两者都可以,因为 SELECT INTO 会覆盖它)
v_pass := '';
-- 使用明确的别名来引用表列,尽管在这个例子中不是必需的
SELECT item_value INTO v_pass
FROM kcrp_dict_trans A
WHERE A.src_sys_no = p_src_sys_no -- 使用参数别名 p_src_sys_no
AND A.dict_type = p_dict_type -- 使用参数别名 p_dict_type
AND A.dict_id = p_dict_id; -- 使用参数别名 p_dict_id
-- 返回查询到的密码,如果没有查询到结果,则 v_pass 将保持为 ''
RETURN v_pass;
END;