动态查询拼接错误,一个函数使用falie

Dynamic query splicing error,a fuction use falie

我想使用游标获取我需要的模式下所有表中的计数(数据)。

但是我对SQL不熟悉,还是无法通过下面的代码:


CREATE OR REPLACE FUNCTION check_tool.get_nae(v_dbName character varying)
 RETURNS numeric
 LANGUAGE edbspl
 SECURITY DEFINER
AS $function$

    numInsert numeric;
    numCal numeric;
    v_result numeric;
    query TEXT DEFAULT '';

    cursor c_pj is 
        select t.table_schema::text as tableSchema,
            t.table_name::text as tableName
        from information_schema.tables t
        where t.table_catalog = v_dbName
        and t.table_type = 'BASE TABLE'
        and t.table_schema in (select schema_name from check_tool.img_schema where dbName = v_dbName);

BEGIN
    v_result := -1;
    numInsert := 0;
    for r_pj in c_pj loop
        query := 'select count(*) from '||tableSchema||'.'||tableName||';';     -- select count(*) from "item"."project";
        execute query into numCal;

        insert into check_tool.img_result(schema_name,table_name,num) values (r_pj.tableSchema,r_pj.tableName,numCal);

        numInsert := numInsert + 1;
        if numInsert > 1000 then
            numInsert := 0;
            commit;
        end if;
    end loop;
    commit;

    v_result := 0;
    RETURN v_result;
EXCEPTION
    WHEN others THEN
        RETURN v_result;
END get_nae$function$
;
/

我也尝试了concat()和quote_ident(),但是结果并不理想

动态 SQL 应使用 format() 构建以更好地处理标识符。在 Postgres 中,您不能 commit 在函数内部,只能在过程中。在一个循环中提交很少会提高开始时的性能,所以我会跳过它。我也不会隐藏真正的错误(通过只返回 -1 或 0),而只是让任何异常到达过程的调用者。 language edbspl 是我所不知道的,但是在 PL/pgSQL 中我会这样写:

CREATE OR REPLACE PROCEDURE check_tool.get_nae(v_dbName character varying)
 LANGUAGE plpgsql
AS 
$body$
declare --<< required in PL/pgSQL to declare variables
  numcal numeric;
  query TEXT DEFAULT '';
  l_rec record;
BEGIN
  for l_rec in  select t.table_schema::text as tableschema, t.table_name::text as tablename
                from information_schema.tables t
                where t.table_catalog = v_dbName
                and t.table_type = 'BASE TABLE'
                and t.table_schema in (select schema_name from check_tool.img_schema where dbName = v_dbName)
  loop
    query := format('select count(*) from %I.%I', l_rec.tableschema, l_rec.tablename);
    execute query into numcal;

    insert into check_tool.img_result(schema_name,table_name,num) values (l_rec.tableschema, l_rec.tablename, numcal);
  end loop;
  commit;
  
END;
$body$
;

注意条件t.table_catalog = v_dbName实际上是没有用的,因为无论如何你都不能查询不在当前数据库中的表。


请注意,您实际上不需要存储过程来执行此操作。您可以使用 query_to_xml() 通过调整 this answer

在单个 SQL 查询中执行此操作
insert into check_tool.img_result(schema_name,table_name,num) 
select table_schema, 
       table_name, 
       (xpath('/row/cnt/text()', xml_count))[1]::text::int as row_count
from (
  select table_name, table_schema, 
         query_to_xml(format('select count(*) as cnt from %I.%I', table_schema, table_name), false, true, '') as xml_count
  from information_schema.tables
  where t.table_type = 'BASE TABLE'
  and t.table_schema in (select schema_name from check_tool.img_schema)
) t;