如何参数化 Postgres-custom-function 中的表和列,如果值存在则选择 PK,否则插入并返回 PK?

Posted

技术标签:

【中文标题】如何参数化 Postgres-custom-function 中的表和列,如果值存在则选择 PK,否则插入并返回 PK?【英文标题】:How do I parameterize table & column in a Postgres-custom-function, selecting PK if value exists, otherwise insert it and return PK anyways? 【发布时间】:2022-01-16 22:28:12 【问题描述】:

尝试执行我在标题中指定的操作,我已经让 upsert 功能正常工作,但是当我尝试对其进行参数化时,我只是超出了我的深度,无法调试它。

我的查询:

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');

【问题讨论】:

那么在这个例子中这不应该是一个问题吗?:dbfiddle.uk/… 你的第二个语句execute 'INSERT INTO ' || target_column_input || ... 听起来很奇怪:target_column_input 应该是一个表的名称,是吗? 哦,现在我意识到你想说什么了,你当然是对的,那是一个疏忽!我仍然得到同样的错误 在您的 SELECT 语句中,INTO 子句必须在 SELECT 子句之后和 FROM 子句之前:SELECT id INTO pk_output FROM ... @aufkeinsten 这就是您要找的东西吗? dbfiddle.uk/… 【参考方案1】:

不要像这样连接字符串。 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

【讨论】:

ty 再次不仅是为了解决方案,也是为了很好的解释,帮了我很多

以上是关于如何参数化 Postgres-custom-function 中的表和列,如果值存在则选择 PK,否则插入并返回 PK?的主要内容,如果未能解决你的问题,请参考以下文章

jmeter中的参数化

如何模板化一个接受模板化参数并在 C++ 中对其应用模板化函数的函数?

NHibernate - 如何使用参数值记录命名参数化查询?

这个参数化查询如何防止 SQL 注入?

如何参数化 Kubeflow Pipelines 环境变量?

参数化查询如何帮助防止 SQL 注入?