Postgresql PL/pgSQL在EXECUTE中创建或替换
我有以下脚本来动态地将视图创建到PostgreSQL数据库中Postgresql PL/pgSQL在EXECUTE中创建或替换,postgresql,plpgsql,dynamic-sql,materialized-views,Postgresql,Plpgsql,Dynamic Sql,Materialized Views,我有以下脚本来动态地将视图创建到PostgreSQL数据库中 CREATE OR REPLACE FUNCTION cs_refresh_mviews() RETURNS integer AS $$ DECLARE mviews RECORD; query text; park_name text; ppstatements int; BEGIN RAISE NOTICE 'Creating views...'; FOR mviews IN SE
CREATE OR REPLACE FUNCTION cs_refresh_mviews() RETURNS integer AS $$
DECLARE
mviews RECORD;
query text;
park_name text;
ppstatements int;
BEGIN
RAISE NOTICE 'Creating views...';
FOR mviews IN SELECT name FROM "Canadian_Parks" LOOP
park_name := mviews.name;
RAISE NOTICE 'Creating or replace view %s...', mviews.name;
query := 'CREATE OR REPLACE VIEW %_view AS
SELECT * from "Canadian_Parks" where name=''%'';
ALTER TABLE %_view OWNER TO postgres', park_name, park_name, park_name;
-- RAISE NOTICE query;
EXECUTE query;
END LOOP;
RAISE NOTICE 'Done refreshing materialized views.';
RETURN 1;
END;
$$ LANGUAGE plpgsql;
我已确认字符串的完整性,例如
CREATE OR REPLACE VIEW Saguenay_St__Lawrence_view AS
SELECT * from "Canadian_Parks" where name='Saguenay_St__Lawrence';
ALTER TABLE Saguenay_St__Lawrence_view OWNER TO postgres
通过手动将其提交到数据库并获得成功响应来分配给查询变量
但是,如果我尝试使用
SELECT cs_refresh_mviews();
将显示以下错误:
ERROR: query "SELECT 'CREATE OR REPLACE VIEW %_view AS SELECT * from "Canadian_Parks" where name=''%''; ALTER TABLE %_view OWNER TO postgres', park_name, park_name, park_name" returned 4 columns
CONTEXT: PL/pgSQL function "cs_refresh_mviews" line 32 at assignment
********** Error **********
ERROR: query "SELECT 'CREATE OR REPLACE VIEW %_view AS SELECT * from "Canadian_Parks" where name=''%''; ALTER TABLE %_view OWNER TO postgres', park_name, park_name, park_name" returned 4 columns
SQL state: 42601
Context: PL/pgSQL function "cs_refresh_mviews" line 32 at assignment
为什么要将其转换为SELECT语句,而不是纯CREATE语句?您误解了逗号在赋值表达式中的用法。 它将
查询
转换为数组(记录
),而不是标量。
使用串联:
park_name := quote_ident(mviews.name||'_view');
query := 'CREATE OR REPLACE VIEW '||park_name||' AS SELECT * from "Canadian_Parks" where name='||quote_literal(mviews.name)||'; ALTER TABLE '||park_name||' OWNER TO postgres';
你的设置很扭曲。为什么要将视图名称的一部分保存在表的复合类型中,而不是保存在纯文本列中 无论如何,它可以这样工作: 设置匹配问题: 要点
- 当您使用execute执行文本时,需要防止SQL注入。我将函数用于标识符和文本
- 我使用语法
来处理您奇怪的设置,并立即提取我们需要的SELECT(name).name
name
- 类似地,视图需要读取
才能在此设置中工作WHERE(name).name=..
- 我消除了许多与问题无关的噪音
- 让函数
也可能没有意义。只需使用返回1
定义函数即可。不过,我保留了它,以便与问题相匹配返回void
CREATE SCHEMA x;
SET search_path = x;
CREATE TABLE canadian_parks (id serial primary key, name text);
INSERT INTO canadian_parks(name) VALUES ('canadian'), ('islandic');
SELECT * from canadian_parks;
CREATE OR REPLACE FUNCTION cs_refresh_mviews()
RETURNS void LANGUAGE plpgsql SET search_path = x AS
$func$
DECLARE
parkname text;
BEGIN
FOR parkname IN SELECT name FROM canadian_parks LOOP
EXECUTE format('
CREATE OR REPLACE VIEW %1$I AS
SELECT * FROM canadian_parks WHERE name = %2$L;
ALTER TABLE %1$I OWNER TO postgres'
, parkname || '_view', parkname);
END LOOP;
END
$func$;
SELECT cs_refresh_mviews();
DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
SET search_path = x;
CREATE TABLE canadian_parks (id serial primary key, name text);
INSERT INTO canadian_parks(name) VALUES ('canadian'), ('islandic');
SELECT * from canadian_parks;
CREATE OR REPLACE FUNCTION cs_refresh_mviews()
RETURNS void LANGUAGE plpgsql SET search_path = x AS
$func$
DECLARE
parkname text;
BEGIN
FOR parkname IN SELECT name FROM canadian_parks LOOP
EXECUTE format('
CREATE OR REPLACE VIEW %1$I AS
SELECT * FROM canadian_parks WHERE name = %2$L;
ALTER TABLE %1$I OWNER TO postgres'
, parkname || '_view', parkname);
END LOOP;
END
$func$;
SELECT cs_refresh_mviews();
DROP SCHEMA x CASCADE;