我需要获取具有空值的特定列的行计数,并将相同的行计数输出插入到具有查询结果集的表中。对于这个要求,我尝试在 postgres 中使用下面的 pl/sql 代码块,但它不起作用,因为我收到以下错误。有人可以建议我在这里做错了什么吗?
SQL Error [42601]: ERROR: syntax error at or near "null"
Where: PL/pgSQL function inline_code_block line 14 at EXECUTE
DO $$
DECLARE
tab RECORD;
l_schema VARCHAR := 'test';
l_sql text;
l1_sql text;
RSE_ROW_COUNT int;
BEGIN
for tab in (select table_name,column_name from INFORMATION_SCHEMA.columns where table_schema='public' and is_nullable='NO' and data_type not in ('integer')
and column_default is null order by table_name,column_name)
LOOP
l_sql := format('SELECT COUNT(1) FROM ' || tab.table_name || 'where ' || tab.column_name || 'is null');
RAISE NOTICE '%', l_sql;
EXECUTE l_sql INTO RSE_ROW_COUNT;
l1_sql := 'INSERT INTO RSE_TABLE_COUNT (TABLE_NAME, Table_column_name,ROW_COUNT, DATE_LAST_UPDATED)
VALUES ( '|| tab.table_name ||','|| tab.column_name ||','|| rse_row_count ||','|| 'SYSDATE)';
RAISE NOTICE '%', l1_sql;
EXECUTE l1_sql;
end loop;
end
$$;
尝试了多种选项但无法修复。
@Paul T. 正确显示了第一个问题 - 列名称和
IS
关键字之间缺少空格。
这种使用动态 SQL 值的方式可能很危险(容易受到 SQL 注入攻击)。您应该使用带有正确占位符的函数
format
或函数 quote_ident
。您使用函数 format
,但不正确:
l_sql := format('SELECT COUNT(1) FROM %I where %I is null', tab.table_name, tab.column_name);
我看到另一个问题 - Postgres 无法运行
sysdate
。请使用 current_date
来代替。
还有很多需要改进的地方,尤其是format()的使用。在当前的方法中,当参数不是标准 PostgreSQL 格式或者甚至容易发生 SQL 注入时,查询仍然会失败。您没有使用占位符和正确的类型。
DO
$$
DECLARE
tab RECORD;
l_schema VARCHAR := 'test';
l_sql TEXT;
l1_sql TEXT;
rse_row_count INT;
BEGIN
FOR tab IN (SELECT table_name, column_name
FROM information_schema.columns
WHERE table_schema = l_schema -- Correct?
AND is_nullable = 'NO'
AND data_type NOT IN ('integer')
AND column_default IS NULL
ORDER BY table_name, column_name)
LOOP
-- use placeholders for Identifiers:
l_sql := FORMAT('SELECT COUNT(1) FROM %I.%I WHERE %I IS NULL;'
, l_schema -- Correct?
, tab.table_name
, tab.column_name
);
RAISE NOTICE '%', l_sql;
EXECUTE l_sql INTO rse_row_count;
l1_sql := FORMAT('INSERT INTO RSE_TABLE_COUNT (TABLE_NAME, Table_column_name,ROW_COUNT, DATE_LAST_UPDATED)
VALUES (%L,%L,%L, %L);'
, tab.table_name
, tab.column_name
, rse_row_count
, NOW()
);
RAISE NOTICE '%', l1_sql;
EXECUTE l1_sql;
END LOOP;
END;
$$;