postgresql - PL/pgSQL 在 EXECUTE 中创建或替换

标签 postgresql plpgsql dynamic-sql materialized-views

我有以下脚本来动态创建 PostgreSQL 数据库的 View 。

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?

最佳答案

您的设置非常扭曲。为什么要将 View 名称的一部分保存在表格的复合类型中,而不是将其保存在纯文本列中?

无论如何,它可以像这样工作:

设置匹配题:

CREATE SCHEMA x;  -- demo in test schema
SET search_path = x;
CREATE TYPE mviews AS (id int, name text); -- composite type used in table

CREATE TABLE "Canadian_Parks" (name mviews);
INSERT INTO "Canadian_Parks"(name) VALUES
 ('(1,"canadian")')
,('(2,"islandic")');  -- composite types, seriously?

SELECT name, (name).* from "Canadian_Parks";

CREATE OR REPLACE FUNCTION cs_refresh_mviews()
  RETURNS int LANGUAGE plpgsql SET search_path = x AS  -- search_path for test
$func$
DECLARE
    _parkname text;
BEGIN

FOR _parkname IN SELECT (name).name FROM "Canadian_Parks" LOOP
   EXECUTE format('
      CREATE OR REPLACE VIEW %1$I AS
      SELECT * FROM "Canadian_Parks" WHERE (name).name = %2$L;
      ALTER TABLE %1$I OWNER TO postgres'
      , _parkname || '_view', _parkname);
END LOOP;

RETURN 1;

END
$func$;

SELECT cs_refresh_mviews();

DROP SCHEMA x CASCADE; -- clean up

要点

  • 当您使用 execute 执行文本时,您需要防止SQL 注入(inject)。我用 format() 标识符文字

  • 的函数
  • 我使用语法 SELECT (name).name 来应对您奇怪的设置并立即提取我们需要的 name

  • 同样,VIEW 需要读取 WHERE (name).name = .. 才能在此设置中工作。

  • 我删除了很多与问题无关的噪音。

  • RETURN 1 函数也可能毫无意义。只需使用 RETURNS 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;

关于postgresql - PL/pgSQL 在 EXECUTE 中创建或替换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12807235/

相关文章:

postgresql - pl/pgSQL - "WHERE IN"子句中使用的参数的正确数据?

ruby-on-rails - 使用 Rails,我如何查询数据库以获取合计数字并按周分组?

ruby-on-rails - 列在 PostgreSQL 数据库和 Rails 3 应用程序中不存在错误

arrays - 访问复合数组元素 plpgsql

mysql - 将表行连接到列中,列标题来自原始行

postgresql - 使用 setSingleRowMode libpq 时返回行号 0 超出范围 0..-1

function - 函数中 EXISTS 子句的性能不佳

c++ - 在 C++ 代码中处理 PL/pgSQL 函数的消息

function - 使用动态 sql 返回多个结果(postgresql 8.2)

sql-server - 在 SQL 中使用变量并在 SQL Server Management Studio 中保持格式设置