【问题标题】:postgresql for loop script in text form can not be executed无法执行文本形式的postgresql for循环脚本
【发布时间】:2021-06-24 15:27:08
【问题描述】:

我正在尝试在 postgresql 中编写函数,该函数创建带有 table_name 文本列的 temp_table,table_rec jsonb 并用我的表中的表名填充它,其中包含 json 中的表和记录的名称。我在字符串中有 for 循环,我想执行它。 但它不起作用。 我有变量 rec 记录、sql_query 文本和 tab_name 文本,我想这样做:

     CREATE OR REPLACE FUNCTION public.test51(
    )
    RETURNS TABLE(tabel_name text, record_json jsonb) 
    LANGUAGE 'plpgsql'

    COST 100
    VOLATILE 
    ROWS 1000
    
AS $BODY$
declare
rec record;
tabel_name text;
tabel_names text[];
counter integer := 1;
sql_query text;
limit_for_sending integer;
rec_count integer;
begin
select into tabel_names array(select "TABLE_NAME" from public."TABLES");
create temp table temp_tab(tab_nam text, recik jsonb);

while array_length(tabel_names, 1) >= counter loop

tabel_name := '"' || tabel_names[counter] || '"';

select into limit_for_sending "TABLE_LIMIT_FOR_SENDING_DATA" from public."TABLES" where "TABLE_NAME" = tabel_name;

sql_query := 'select count(*) from public.' || tabel_name;

execute sql_query into rec_count;

if (rec_count >= limit_for_sending and limit_for_sending is not null) then

sql_query := 'for rec in select * from public.' || tabel_name || '
loop
    insert into temp_tab
    select ' || tabel_name || ', to_jsonb(rec);
end loop';

execute sql_query;

end if;

counter := counter + 1;

end loop;

return query
select * from temp_tabik;

drop table temp_tabik;
end;
$BODY$;

感谢您的回复。

【问题讨论】:

  • 感谢您的回复。我知道 temp_table 没用。该功能不是最终的,我不想创建新表。我对执行变量 sql_script 感到好奇。我知道我可以执行 DDL 和 DML 脚本,但我不知道是否可以以相同的方式执行 for 循环和条件。我现在将更新代码。
  • “但它不起作用......我想这样做:(一些sql代码)”?现在我们需要猜测您想用该代码做什么?尝试将您的问题变成minimal reproducible example。添加示例输入和预期输出。

标签: postgresql for-loop execute control-structure


【解决方案1】:

您似乎有一些表,其中包含您希望将所有行作为 JSONB 返回的表的信息。并且该元表还包含一列,该列设置了不应返回行的阈值。

您不需要临时表或数组来存储表名。您可以遍历 TABLES 表上的查询并直接在该循环中运行动态 SQL。

PL/pgSQL 中的return query 不会终止函数,它只是将查询结果附加到函数结果中。

最好使用 format() 函数创建动态 SQL,因为它更易于阅读,并且使用 %I 占位符将正确处理带引号的标识符(这对于您使用那些可怕的大写表名非常重要)

据我所知,您的功能可以简化为:

CREATE OR REPLACE FUNCTION public.test51()
    RETURNS TABLE(tabel_name text, record_json jsonb) 
    LANGUAGE plpgsql
AS 
$BODY$
declare
  rec record;
  sql_query text;
  rec_count bigint;
begin
  for rec in 
      select "TABLE_NAME" as table_name, "TABLE_LIMIT_FOR_SENDING_DATA" as rec_limit
      from public."TABLES"
  loop
    
    if rec.rec_limit is not null then 
      execute format('select count(*) from %I', rec.table_name)
        into rec_count;
    end if;
    
    if (rec.rec_limit is not null and rec_count >= rec.rec_limit) then 
      sql_query := format('select %L, to_jsonb(t) from %I as t', rec.table_name, rec.table_name);
      return query execute sql_query;
    end if;

  end loop;
end;
$BODY$;

一些笔记

  • 语言名称是一个标识符,不应用单引号括起来。此语法已弃用,可能会在未来版本中删除,因此请不要习惯它。
  • 你真的应该避免那些可怕的带引号的标识符。他们的麻烦比他们的价值要多得多。详情请见the Postgres wiki

【讨论】:

  • 非常感谢。你发布的每一点信息对我来说都非常有价值,因为我只是 postgres 和数据库的初学者。这将帮助我解决工作中的问题:) 谢谢
  • 完成,对不起,这是我第一次使用堆栈溢出,所以我不知道这里的绳索。再次感谢您的回答,祝您有愉快的一天。
猜你喜欢
  • 2017-05-11
  • 1970-01-01
  • 2019-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-04
相关资源
最近更新 更多