Postgres 中的动态 SQL

Posted

技术标签:

【中文标题】Postgres 中的动态 SQL【英文标题】:Dynamic SQL in Postgres 【发布时间】:2014-04-04 14:48:10 【问题描述】:

我使用 Postgres 编写了一个简单的函数,但不断得到以下信息:

错误:“$2”处或附近的语法错误。

底层数据库是 ParAccel,我是 Postgres 和 ParAccel 的新手。我使用 TOAD 数据点作为 IDE:

CREATE OR REPLACE FUNCTION GET_NEXT_SURR_KEY(I_SCHEMA_NM VARCHAR, I_TABLE_NM VARCHAR,I_COLUMN_NM VARCHAR,I_POSNEG_FLAG VARCHAR) 
RETURNS BIGINT
LANGUAGE PLPGSQL
AS $body$
DECLARE
    O_RET_VALUE BIGINT := 0;
    V_DYN_SQL VARCHAR(2000) := '';
BEGIN
    IF I_POSNEG_FLAG = 'P' THEN
       V_DYN_SQL := 'SELECT MAX(' || I_COLUMN_NM || ') + 1 FROM ' || I_SCHEMA_NM || '.' || I_TABLE_NM;

    ELSE
       V_DYN_SQL := 'SELECT MIN(' || I_COLUMN_NM || ') - 1 FROM ' || I_SCHEMA_NM || '.' || I_TABLE_NM;
    END IF;

    EXECUTE V_DYN_SQL INTO O_RET_VALUE;

    RETURN O_RET_VALUE;
END $body$

我正在使用以下示例命令来执行函数:

CALL GET_NEXT_SURR_KEY('some_schema_name','some_table_name','some_column_name','P');

谁能告诉我我在哪里搞砸了?

提前致谢。

【问题讨论】:

你为什么不使用序列?使用 select max() 获取唯一 ID 不起作用,而且速度也很慢。 +1 以上。这是完全错误的设计。见***.com/questions/2944297/… 不在 ParAccel 上使用 Sequencer 是车间的设计决定,不在我的控制范围内,目前正在 DB2 上完成。如果我使用硬编码的列名和表名,则选择 Max() 可以正常工作。响应时间不是问题,因为音量很低。所以回到我原来的问题.... 呃,构造动态 SQL 时不要使用||。将format 函数与%I 格式说明符一起使用。它会为您正确报价。或者至少使用quote_ident select max() NOT “工作正常”。在一个与数据库有多个并发连接的环境中,这一概念显然被打破了。 非常您至少需要做的是在运行选择之前完全 锁定表。 【参考方案1】:

ParAccel 有 IDENTITY 字段的概念,不知道你为什么不使用它们。

但无论如何,这里是如何解决您的问题。

顺便说一句,我相信您编写的代码可以在 PostgreSQL 9 或更高版本上运行,但 ParAccel 使用的是不支持 SELECT INTO 变量的版本 7.02(如果我没记错的话),因此您需要使用一条记录并使用循环提取值(我没有重写你的所有函数,只是主要部分)

CREATE OR REPLACE FUNCTION GET_NEXT_SURR_KEY(I_SCHEMA_NM VARCHAR, I_TABLE_NM VARCHAR,I_COLUMN_NM VARCHAR,I_POSNEG_FLAG VARCHAR) 
RETURNS BIGINT
LANGUAGE PLPGSQL
AS $body$
DECLARE
    O_RET_VALUE BIGINT default 0;
    V_DYN_SQL VARCHAR(2000) := '';
    _ret_rec record; 
BEGIN


     V_DYN_SQL := 'SELECT MAX(' || I_COLUMN_NM || ') + 1 as new_id FROM ' || I_SCHEMA_NM || '.' || I_TABLE_NM;

    FOR _ret_rec IN EXECUTE V_DYN_SQL 
    LOOP 
        O_RET_VALUE := _ret_rec.new_id; 
    END LOOP; 


    RETURN O_RET_VALUE;
END $body$

【讨论】:

谢谢迭戈!!!那行得通!我非常感谢您的反馈... 至于为什么我们不使用 Identity 列,是因为我们必须将大约 500 个作业从 DB2 迁移到 ParAccel,并且希望最大限度地减少迁移的更改。再次感谢【参考方案2】:

相信马,使用序列 - 因为您在 OLAP 环境中,您很可能不会违反唯一性,但如果这是一个正常的网站,您会经常两次获得相同的 id。至于你的函数,它工作得很好——在我数据库中的一个随机表上对其进行了测试,没有给出错误,所以在 TOAD 中查找错误。

【讨论】:

感谢您测试代码。不,它不是蟾蜍。我使用 DBVisualizer 创建了相同的函数,但仍然出现相同的错误。它与 ParAccel 和 PostgreSQL 有关,它们似乎不太好说话。不幸的是,没有本地 ParAccel 驱动程序(目前),所以暂时必须通过 PostgreSQL 来访问 ParAccel

以上是关于Postgres 中的动态 SQL的主要内容,如果未能解决你的问题,请参考以下文章

postgres中的动态sql查询

Postgres 中的动态 UNION ALL 查询

如何在带有 Postgres 的动态框架中使用窗口函数中的列值?

如何使用动态正则表达式匹配 Postgres 中的值

Postgres 从动态 sql 字符串创建本地临时表(在提交删除时)

Postgres 交叉表动态列数