在 Oracle PL_SQL 函数中将列名作为参数传递
Passing column name as parameter in Oracle PL_SQL function
我正在尝试传递两个输入参数,列名和 table 名称。然后该函数应输出如下定义的字符串值:
create or replace function get_id5(in_col_name IN VARCHAR2,in_tbl_name IN VARCHAR2)
return VARCHAR2
is
/*in_col_nm varchar(32) := in_col_name;
/*in_tbl_nm varchar(64) := in_tbl_name; */
integer_part NUMBER ;
integer_part_str VARCHAR2(32) ;
string_part VARCHAR2(32) ;
full_id VARCHAR2(32) ;
out_id VARCHAR(32) ;
BEGIN
/*select MAX(in_col_nm) INTO full_id FROM in_tbl_nm ; */
execute immediate 'select MAX('||in_col_name||') FROM' || in_tbl_name ||'INTO' || full_id;
/*select regexp_replace(full_id , '[^0-9]', '') INTO integer_part_str , regexp_replace(full_id , '[^a-z and ^A-Z]', '') INTO string_part from dual ; */
integer_part_str := regexp_replace(full_id , '[^0-9]', '') ;
string_part := regexp_replace(full_id , '[^a-z and ^A-Z]', '') ;
integer_part := TO_NUMBER(integer_part_str);
integer_part := integer_part + 1 ;
integer_part_str := TO_CHAR(integer_part) ;
out_id := string_part + integer_part_str ;
return out_id;
END;
我在数据库中有一个名为 BRANDS 的 table,列 BRAND_ID 的最大值是 'Brand05'。预期输出为 'Brand06'.
然而当我运行:
select get_id5('BRAND_ID' , 'BRANDS') from dual;
或
DECLARE
a VARCHAR(32) ;
BEGIN
a := get_id5('BRAND_ID' , 'BRANDS');
END;
我收到以下错误:
ORA-00923: FROM keyword not found where expected
FROM
和 table_name 之间需要空格,INTO
应该在 SQL 文本之外:
execute immediate 'select MAX('||in_col_name||') FROM ' || in_tbl_name INTO full_id;
您也可以使用 DBMS_ASSERT
:
execute immediate 'select MAX('||DBMS_ASSERT.SIMPLE_SQL_NAME(in_col_name)||') FROM ' || DBMS_ASSERT.SIMPLE_SQL_NAME(in_tbl_name) INTO full_id;
然后你需要使用 ||
作为字符串连接运算符(而不是 +
)。
您的函数可以是:
create or replace function get_id5(
in_col_name IN VARCHAR2,
in_tbl_name IN VARCHAR2
) RETURN VARCHAR2
IS
full_id VARCHAR2(32);
BEGIN
execute immediate 'select MAX('||DBMS_ASSERT.SIMPLE_SQL_NAME(in_col_name)||') '
|| 'FROM ' || DBMS_ASSERT.SIMPLE_SQL_NAME(in_tbl_name)
INTO full_id;
return regexp_replace(full_id , '\d+', '')
|| TO_CHAR(regexp_replace(full_id , '\D+', '') + 1);
END;
/
示例数据:
CREATE TABLE brands (brand_id) AS
SELECT 'BRAND5' FROM DUAL;
然后:
select get_id5('BRAND_ID' , 'BRANDS') AS id from dual;
输出:
ID
BRAND6
db<>fiddle here
更好的解决方案
要生成数字,请使用 SEQUENCE
或 Oracle 12 中的 IDENTITY
列,如果您必须有字符串前缀,则使用虚拟列来生成它。
CREATE TABLE brands(
ID NUMBER
GENERATED ALWAYS AS IDENTITY
PRIMARY KEY,
brand_id VARCHAR2(10)
GENERATED ALWAYS
AS (CAST('BRAND' || TO_CHAR(id, 'FM000') AS VARCHAR2(10)))
);
BEGIN
INSERT INTO brands (id) VALUES (DEFAULT);
INSERT INTO brands (id) VALUES (DEFAULT);
INSERT INTO brands (id) VALUES (DEFAULT);
END;
/
SELECT * FROM brands;
输出:
ID
BRAND_ID
1
BRAND001
2
BRAND002
3
BRAND003
db<>fiddle here
我正在尝试传递两个输入参数,列名和 table 名称。然后该函数应输出如下定义的字符串值:
create or replace function get_id5(in_col_name IN VARCHAR2,in_tbl_name IN VARCHAR2)
return VARCHAR2
is
/*in_col_nm varchar(32) := in_col_name;
/*in_tbl_nm varchar(64) := in_tbl_name; */
integer_part NUMBER ;
integer_part_str VARCHAR2(32) ;
string_part VARCHAR2(32) ;
full_id VARCHAR2(32) ;
out_id VARCHAR(32) ;
BEGIN
/*select MAX(in_col_nm) INTO full_id FROM in_tbl_nm ; */
execute immediate 'select MAX('||in_col_name||') FROM' || in_tbl_name ||'INTO' || full_id;
/*select regexp_replace(full_id , '[^0-9]', '') INTO integer_part_str , regexp_replace(full_id , '[^a-z and ^A-Z]', '') INTO string_part from dual ; */
integer_part_str := regexp_replace(full_id , '[^0-9]', '') ;
string_part := regexp_replace(full_id , '[^a-z and ^A-Z]', '') ;
integer_part := TO_NUMBER(integer_part_str);
integer_part := integer_part + 1 ;
integer_part_str := TO_CHAR(integer_part) ;
out_id := string_part + integer_part_str ;
return out_id;
END;
我在数据库中有一个名为 BRANDS 的 table,列 BRAND_ID 的最大值是 'Brand05'。预期输出为 'Brand06'.
然而当我运行:
select get_id5('BRAND_ID' , 'BRANDS') from dual;
或
DECLARE
a VARCHAR(32) ;
BEGIN
a := get_id5('BRAND_ID' , 'BRANDS');
END;
我收到以下错误:
ORA-00923: FROM keyword not found where expected
FROM
和 table_name 之间需要空格,INTO
应该在 SQL 文本之外:
execute immediate 'select MAX('||in_col_name||') FROM ' || in_tbl_name INTO full_id;
您也可以使用 DBMS_ASSERT
:
execute immediate 'select MAX('||DBMS_ASSERT.SIMPLE_SQL_NAME(in_col_name)||') FROM ' || DBMS_ASSERT.SIMPLE_SQL_NAME(in_tbl_name) INTO full_id;
然后你需要使用 ||
作为字符串连接运算符(而不是 +
)。
您的函数可以是:
create or replace function get_id5(
in_col_name IN VARCHAR2,
in_tbl_name IN VARCHAR2
) RETURN VARCHAR2
IS
full_id VARCHAR2(32);
BEGIN
execute immediate 'select MAX('||DBMS_ASSERT.SIMPLE_SQL_NAME(in_col_name)||') '
|| 'FROM ' || DBMS_ASSERT.SIMPLE_SQL_NAME(in_tbl_name)
INTO full_id;
return regexp_replace(full_id , '\d+', '')
|| TO_CHAR(regexp_replace(full_id , '\D+', '') + 1);
END;
/
示例数据:
CREATE TABLE brands (brand_id) AS
SELECT 'BRAND5' FROM DUAL;
然后:
select get_id5('BRAND_ID' , 'BRANDS') AS id from dual;
输出:
ID BRAND6
db<>fiddle here
更好的解决方案
要生成数字,请使用 SEQUENCE
或 Oracle 12 中的 IDENTITY
列,如果您必须有字符串前缀,则使用虚拟列来生成它。
CREATE TABLE brands(
ID NUMBER
GENERATED ALWAYS AS IDENTITY
PRIMARY KEY,
brand_id VARCHAR2(10)
GENERATED ALWAYS
AS (CAST('BRAND' || TO_CHAR(id, 'FM000') AS VARCHAR2(10)))
);
BEGIN
INSERT INTO brands (id) VALUES (DEFAULT);
INSERT INTO brands (id) VALUES (DEFAULT);
INSERT INTO brands (id) VALUES (DEFAULT);
END;
/
SELECT * FROM brands;
输出:
ID BRAND_ID 1 BRAND001 2 BRAND002 3 BRAND003
db<>fiddle here