使用表值变量执行 PostgreSQL 动态查询

问题描述 投票:0回答:1

我正在使用 PostgreSQL pgsql 函数内部的代码。 我有一个合并语句,其中包含多个仅在运行时才知道的元素,并作为参数提供给函数,这需要我将合并语句构建为我执行的动态 SQL 语句。 这些动态元素包括合并的目标表和源数据,我将其作为复合记录数组。

如何将复合记录数组传递到执行语句中,以便合并正常工作? 我知道如何在动态语句中使用数据值、列名和表名,但我还没有破解如何传入表或值数组。

我似乎不知道如何使用 unnest 来做到这一点。 本地临时表似乎在执行事务中没有作用域。 在合并中直接引用的常规表会在函数的并行执行中产生争用和问题。

CREATE TEMPORARY TABLE bulk_data_table OF dbo."compositerecordtype";
INSERT INTO bulk_data_table (cola, colb, colc) SELECT BM.cola, BM.colb, BM.colc FROM UNNEST("user_bulk_data"::compositerecordtype) AS BM;

dynamic_sqlStatement := 
'MERGE INTO ' || "TableName" || ' AS TRG 
USING (SELECT cola, colb, colc FROM ' || bulk_data_table || ' AS SRC
ON (TRG.id = SRC.id)
WHEN NOT MATCHED THEN
    INSERT (cola, colb, colc) VALUES (SRC.cola, SRC.colb, SRC.colc)
WHEN MATCHED THEN
    UPDATE SET colb = SRC.colb, colc = SRC.colc;';

EXECUTE dynamic_sqlStatement
postgresql dynamic scope execute
1个回答
0
投票
  1. 根本不要将目标
    "TableName"
    传递到函数中。相反,使用该表名称来转换传入数组。
  2. 在函数内部,在
    pg_type
    中查找目标表。所有常规类型都列出了一个数组版本。这意味着根据传入数组的
    pg_typeof()
    ,您可以查找其基本元素类型,这将是目标表。
  3. 该函数可以接受
    anyarray()
    ,这样你就不需要为不同的目标定义多个版本。
  4. 使用位置占位符
    %1$I
    通过
    format()
    将目标表传递到查询中。
  5. 在查询中使用
    $1
    通过
    execute..using
    传递传入的有效负载。

db<>fiddle

演示
create or replace function merge_payload_into_table(
  payload anyarray)returns void as $f$
declare base_type text:=(select typelem::regtype 
                         from pg_type 
                         where oid=pg_typeof(payload)::regtype);
begin execute format(
  $dsql$
  MERGE INTO %1$I AS TRG 
  USING (SELECT id, cola, colb, colc FROM unnest($1::%1$I[]) ) AS SRC
  ON (TRG.id = SRC.id)
  WHEN NOT MATCHED THEN
    INSERT (cola, colb, colc) VALUES (SRC.cola, SRC.colb, SRC.colc)
  WHEN MATCHED THEN
    UPDATE SET colb = SRC.colb, colc = SRC.colc;
  $dsql$, base_type) USING payload;
end $f$ language plpgsql;
  1. 您可以在
    information_schema.columns
    中查找列并动态构建
    merge
    中的列列表,只留下您要匹配的
    id
    是静态的。如果您想完全动态化,您可以在 pg_index
    查找主键
    列或唯一列组合,并让
    merge..on
    条件动态构建。
  2. 架构资格可以改进 - 理想情况下,您也应该查找
    pg_type.typnamespace

一个简单的测试:

create schema dbo;
create table dbo."compositerecordtype"(
   id int generated by default as identity primary key
  ,cola int
  ,colb int
  ,colc int);
set search_path to dbo,public;

insert into "compositerecordtype"(cola,colb,colc) 
values(1,2,3)
returning*;
id 可乐 科尔布 科尔克
1 1 2 3
select merge_payload_into_table(array[ row(1,101,102,103)
                                      ,row(2,201,202,203)
                                      ,row(3,301,302,303)]::compositerecordtype[] );
select*from compositerecordtype;
id 可乐 科尔布 科尔克
1 1 102 103
2 201 202 203
3 301 302 303
© www.soinside.com 2019 - 2024. All rights reserved.