SQL错误42601:在拼接TEXT时出现语法错误
我遇到了如下错误:
[42601] ERROR: syntax error at or near "$3" in context "|| $2 AS $3", at line 1
Where: PL/pgSQL function "create_internal_tables" line 19 at SQL statement
当我尝试运行这里所示的过程来创建表时。
注:我甚至尝试将 v_tgt_tab 和 v_src_tab 声明为 VARCHAR(50),以及使用 CONCAT 函数,但仍然收到相同的错误。
CREATE OR REPLACE PROCEDURE create_internal_tables()
AS $$
DECLARE
v_tgt_tab TEXT;
v_src_tab TEXT;
CNT INT = 0;
wh_tab_rec RECORD;
BEGIN
FOR wh_tab_rec IN
(
SELECT COALESCE(a.schema_name, b.schema_name) as schema_name,
COALESCE(a.table_name, b.table_name) as table_name
FROM svv_all_tables AS a RIGHT OUTER JOIN svv_all_tables b
ON a.schema_name = b.schema_name AND
a.table_name = b.table_name
WHERE a.database_name = 'nonprod'
AND b.database_name = 'warehouse'
ORDER BY b.schema_name, b.table_name
)
LOOP
SELECT 'nonprod.' || wh_tab_rec.schema_name || '.tmp_' || wh_tab_rec.table_name AS v_tgt_tab;
SELECT 'warehouse.' || wh_tab_rec.schema_name || '.' || wh_tab_rec.table_name AS v_src_tab;
RAISE INFO 'Creating destination internal table %', v_tgt_tab;
EXECUTE ('CREATE TABLE %I AS SELECT * FROM %I WHERE 1=0', v_tgt_tab, v_src_tab );
CNT := CNT + 1;
END LOOP;
RAISE NOTICE '% internal tables created in destination.', CNT;
END;
$$ LANGUAGE plpgsql;
CALL create_internal_tables();
基于提供的答案,我对代码进行了如下修改。看起来现在已经可以工作了。
CREATE OR REPLACE PROCEDURE create_table_as_select(
target_table_name IN VARCHAR,
source_table_name IN VARCHAR
)
LANGUAGE plpgsql
AS $$
BEGIN
EXECUTE 'CREATE TABLE ' || target_table_name || ' AS SELECT * FROM ' || source_table_name || ';';
END;
$$;
CREATE OR REPLACE PROCEDURE create_internal_tables()
LANGUAGE plpgsql
AS $$
DECLARE
v_tgt_tab VARCHAR(256);
v_src_tab VARCHAR(256);
CNT INT = 0;
wh_tab_rec RECORD;
BEGIN
FOR wh_tab_rec IN
(
SELECT COALESCE(a.schema_name, b.schema_name) as schema_name,
COALESCE(a.table_name, b.table_name) as table_name
FROM svv_all_tables AS a RIGHT OUTER JOIN svv_all_tables b
ON a.schema_name = b.schema_name AND
a.table_name = b.table_name
WHERE a.database_name = 'nonprod'
AND b.database_name = 'warehouse'
AND b.schema_name NOT LIKE 'pg_%'
AND b.schema_name NOT LIKE 'dbt_%'
AND b.schema_name NOT LIKE 'models%'
AND b.schema_name NOT IN ('information_schema', 'control')
ORDER BY b.schema_name, b.table_name
)
LOOP
v_tgt_tab := 'nonprod.' || wh_tab_rec.schema_name || '.tmp_' || wh_tab_rec.table_name;
v_src_tab := 'warehouse.' || wh_tab_rec.schema_name || '.' || wh_tab_rec.table_name;
--EXECUTE ('CREATE TABLE %I AS SELECT * FROM %I WHERE 1=0', v_tgt_tab, v_src_tab );
CALL create_table_as_select(v_tgt_tab, v_src_tab);
CNT := CNT + 1;
END LOOP;
END;
$$;
CALL create_internal_tables();
解决方案
你不能把变量 (v_tgt_tab) 作为别名使用。PL/pgSQL在执行SQL语句时会把你的变量替换成参数,而参数不能替代像表名、列名或别名这样的标识符。
看看你的代码,似乎你根本不想要别名,而是想给变量赋一个值。应该是如下形式:
v_tgt_tab := 'nonprod.' || wh_tab_rec.schema_name || '.tmp_' || wh_tab_rec.table_name;
你的代码仍然存在许多其他问题:
- 你正在把表引用成
databasename.schemaname.tablename,看起来你想进行跨数据库查询。按照PostgreSQL的设计,这是不可能的。如果你确实想查询不同的数据库,需要使用一个外部数据封装器(FDW)。也许把整件事在客户端实现,而不是在数据库内部,会是更好的解决方案。 - 你把
EXECUTE作为一个函数来使用,并且在EXECUTE与format()函数之间混用,似乎有些奇怪。你需要
EXECUTE format('CREATE TABLE %I ...', tablename);
* 你的 CREATE TABLE 语句(正确地!)使用了标识符的占位符 %I,但这意味着最终会得到像 "schemaname.tablename" 这样的表名,而你真正想要的是 "schemaname"."tablename"。
你需要写成类似于
EXECUTE format('CREATE TABLE %I.%I ...', schemaname, tablename);
如果那段代码是由聊天机器人写的,你应该找一个更靠谱的版本。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。