参数化 Redshift PL/pgSQL 循环中的列名称

问题描述 投票:0回答:2

我需要有关如何使用 SQL(或动态 SQL)编写循环代码的帮助,其中我使用“x”作为列名的占位符。有人有任何建议,这样我就不必为每一列手动运行此语句吗?

CREATE OR REPLACE PROCEDURE PCI_COLUMNS()
AS $$
DECLARE
  x RECORD;
BEGIN
    FOR x IN (select col from L_USA.COLUMNS WHERE TYPE = 'PCI')
    LOOP
        ATTACH MASKING POLICY COMMERCIAL_PCI
        ON L_USA.DEMO(x)
        USING (x, CUST_ID)
        TO ROLE COMM_PCI
        PRIORITY 30;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

上面的代码是我的设想,但它吐出了一个错误

错误:“$1”处或附近的语法错误其中:第 5 行附近 PL/PgSQL 函数“pci_columns”中的 SQL 语句 [ErrorId: 1-6571f613-3df6ae50214fb89252a028fb])

因为我认为我不能像这样参数化对象

sql loops amazon-redshift parameter-passing dynamic-sql
2个回答
0
投票

使用动态 SQL

EXECUTE
。不幸的是,Redshift 没有
format()
(它是在 PostgreSQL 9.1 中添加的,在 Redshift 从 PostgreSQL 8.0.2 分叉之后的一段时间),所以你需要在注入之前 quote_ident()
 你的列名将其写入声明中。

CREATE OR REPLACE PROCEDURE PCI_COLUMNS() AS $$ DECLARE x RECORD; BEGIN FOR x IN (SELECT quote_ident(col) AS quoted_column FROM L_USA.COLUMNS WHERE TYPE = 'PCI') LOOP EXECUTE CONCAT( 'ATTACH MASKING POLICY COMMERCIAL_PCI', 'ON L_USA.DEMO(',x.quoted_column,')', 'USING (',x.quoted_column,', CUST_ID)', 'TO ROLE COMM_PCI', 'PRIORITY 30;'); END LOOP; END; $$ LANGUAGE plpgsql; CALL PCI_COLUMNS();
    

-3
投票
PostgreSQL 不允许使用您尝试的语法直接在动态 SQL 中对列名称进行参数化。但是,您可以通过使用字符串连接来构建动态查询来实现您想要的目的。

这是使用动态 SQL 的存储过程的修改示例:

sql

CREATE OR REPLACE PROCEDURE PCI_COLUMNS() AS $$ DECLARE x RECORD; sql_query TEXT; BEGIN FOR x IN (SELECT col FROM L_USA.COLUMNS WHERE TYPE = 'PCI') LOOP -- Build the dynamic query using string concatenation sql_query := 'ATTACH MASKING POLICY COMMERCIAL_PCI' ' ON L_USA.DEMO(' || x.col || ')' ' USING (' || x.col || ', CUST_ID)' ' TO ROLE COMM_PCI PRIORITY 30;'; -- Execute the dynamic query EXECUTE sql_query; END LOOP; END; $$ LANGUAGE plpgsql;
在此示例中,变量 sql_query 用于使用字符串连接构建动态查询。然后使用 EXECUTE 语句来执行动态查询。

构建动态查询时务必谨慎,避免 SQL 注入等安全漏洞。在这种特定情况下,由于列名来自内部表,因此 SQL 注入的风险很低。但是,如果列名称来自用户输入,那么使用准备好的语句来防止漏洞就很重要。

© www.soinside.com 2019 - 2024. All rights reserved.