如何参数化 table 和 Postgres-custom-function 中的列,如果值存在则选择 PK,否则插入它和 return PK?
How do I parameterize table & column in a Postgres-custom-function, selecting PK if value exists, otherwise insert it and return PK anyways?
尝试执行我在标题中指定的操作,我已经让 upsert-functionalities 正常工作,但是当我尝试对其进行参数化时,我力不从心,无法调试它。
我的查询:
CREATE OR REPLACE FUNCTION custom_upsert(target_value_input text,
target_table_input text,
target_column_input text,
OUT pk_output int)
LANGUAGE plpgsql AS
$func$
BEGIN
LOOP
execute 'SELECT id '
' FROM ' || target_table_input ||
' WHERE ' || target_column_input || ' = ' || target_value_input ||
' INTO pk_output';
EXIT WHEN FOUND;
execute 'INSERT INTO ' || target_table_input || 'AS o ( ' || target_column_input || ' )'
' VALUES ( ' || target_value_input || ' ) '
' ON CONFLICT ( ' || target_column_input || ' ) DO NOTHING '
' RETURNING o.id'
' INTO pk_output';
EXIT WHEN FOUND;
END LOOP;
END
$func$;
现在,当我尝试使用该函数时,我得到:
ERROR: syntax error at or near "INTO"
LINE 1: ...module WHERE artifact_id = artifact_id_example_1 INTO pk_ou...
^
QUERY: SELECT id FROM maven_module WHERE artifact_id = artifact_id_example_1 INTO pk_output
CONTEXT: PL/pgSQL function custom_upsert(text,text,text) line 4 at EXECUTE
令我困惑的是这个语法在未参数化版本中工作正常:
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=765389a746d3a392bc646fbedb7ed3b3
我在参数化方面的尝试:
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=1bffab45d8a9587342a7c3253ea35fc8
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=de6ba235aa21dae33b922f8fddac3b63
非常感谢你,第一次发帖所以如果有什么我应该在提问时做不同的事情,我很高兴收到反馈
编辑:这是我的函数调用:
-- should return pk of existing artifact_id
SELECT custom_upsert('artifact_id_example_1', 'maven_module', 'artifact_id');
-- should return pk of new artifact_id
SELECT custom_upsert('artifact_id_example_2', 'maven_module', 'artifact_id');
不要那样连接字符串。函数 format()
让你的生活更轻松(更安全),例如
EXECUTE format('INSERT INTO %1$I AS o (%2$I)
VALUES (%3$L) ON CONFLICT (%2$I) DO NOTHING RETURNING o.id',
target_table_input,
target_column_input,
target_value_input) INTO pk_output;
%I
会将标识符用双引号括起来,这在表或列区分大小写或包含特殊字符时很方便。
%L
会将文字用单引号括起来
1$
、2$
和3$
是在format()
调用中提供的变量位置,如果一个变量被多次使用,这非常方便。
演示:db<>fiddle
尝试执行我在标题中指定的操作,我已经让 upsert-functionalities 正常工作,但是当我尝试对其进行参数化时,我力不从心,无法调试它。
我的查询:
CREATE OR REPLACE FUNCTION custom_upsert(target_value_input text,
target_table_input text,
target_column_input text,
OUT pk_output int)
LANGUAGE plpgsql AS
$func$
BEGIN
LOOP
execute 'SELECT id '
' FROM ' || target_table_input ||
' WHERE ' || target_column_input || ' = ' || target_value_input ||
' INTO pk_output';
EXIT WHEN FOUND;
execute 'INSERT INTO ' || target_table_input || 'AS o ( ' || target_column_input || ' )'
' VALUES ( ' || target_value_input || ' ) '
' ON CONFLICT ( ' || target_column_input || ' ) DO NOTHING '
' RETURNING o.id'
' INTO pk_output';
EXIT WHEN FOUND;
END LOOP;
END
$func$;
现在,当我尝试使用该函数时,我得到:
ERROR: syntax error at or near "INTO"
LINE 1: ...module WHERE artifact_id = artifact_id_example_1 INTO pk_ou...
^
QUERY: SELECT id FROM maven_module WHERE artifact_id = artifact_id_example_1 INTO pk_output
CONTEXT: PL/pgSQL function custom_upsert(text,text,text) line 4 at EXECUTE
令我困惑的是这个语法在未参数化版本中工作正常:
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=765389a746d3a392bc646fbedb7ed3b3
我在参数化方面的尝试:
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=1bffab45d8a9587342a7c3253ea35fc8
https://dbfiddle.uk/?rdbms=postgres_14&fiddle=de6ba235aa21dae33b922f8fddac3b63
非常感谢你,第一次发帖所以如果有什么我应该在提问时做不同的事情,我很高兴收到反馈
编辑:这是我的函数调用:
-- should return pk of existing artifact_id
SELECT custom_upsert('artifact_id_example_1', 'maven_module', 'artifact_id');
-- should return pk of new artifact_id
SELECT custom_upsert('artifact_id_example_2', 'maven_module', 'artifact_id');
不要那样连接字符串。函数 format()
让你的生活更轻松(更安全),例如
EXECUTE format('INSERT INTO %1$I AS o (%2$I)
VALUES (%3$L) ON CONFLICT (%2$I) DO NOTHING RETURNING o.id',
target_table_input,
target_column_input,
target_value_input) INTO pk_output;
%I
会将标识符用双引号括起来,这在表或列区分大小写或包含特殊字符时很方便。%L
会将文字用单引号括起来1$
、2$
和3$
是在format()
调用中提供的变量位置,如果一个变量被多次使用,这非常方便。
演示:db<>fiddle