【问题标题】:if-statement with string containing the condition带有包含条件的字符串的 if 语句
【发布时间】:2012-02-12 04:04:48
【问题描述】:

这个问题是关于 Postgresql 8.3

我有一个表,其中的字段包含“lastcontact 为空”等条件。在代码中,我想遍历这个表,对于每条记录,我想检查'if condition then',就像在这个例子中一样:

FOR myrec IN
    SELECT * FROM tabel ORDER BY colorlevel, volgnummer
LOOP
    if (myrec.conditie) then
        raise notice 'Condition % is true', myrec.conditie;
    else
        raise notice 'Condition % is false', myrec.conditie;
    end if;
END LOOP;

在这个例子中我称之为'tabel'的表:

ID | Conditie             | Colorlevel | Volgnummer | Code | Description
1  | lastcontact is null  | 1          | 1          | ...  | ...
2  | lastchanged is null  | 1          | 2          | ...  | ...
3  | lastmodified is null | 1          | 3          | ...  | ...

是否可以进行我想要的检查?上面的代码导致如下错误:

ERROR:  invalid input syntax for type boolean: "lastcontact is null"

包含 Erwin 函数结果的新部分

我用过这个功能:

CREATE OR REPLACE FUNCTION foo(lastcontact timestamptz)
  RETURNS void AS
$BODY$
DECLARE
  myrec record;
  mycond boolean;
BEGIN

FOR myrec IN
    SELECT * FROM tabel ORDER BY colorlevel, volgnummer
LOOP
    EXECUTE 'SELECT ' || myrec.conditie || ' FROM tabel' INTO mycond;

    IF mycond then
        RAISE NOTICE 'Condition % is true', myrec.conditie;
    ELSE
        RAISE NOTICE 'Condition % is false', COALESCE(myrec.conditie, 'NULL');
    END IF;
END LOOP;

END;
$BODY$
language 'plpgsql' volatile
cost 100;

我收到此错误:

ERROR:  column "lastcontact" does not exist
LINE 1: SELECT lastcontact is null FROM tabel
           ^
QUERY:  SELECT lastcontact is null FROM tabel
CONTEXT:  PL/pgSQL function "foo" line 9 at EXECUTE statement1

我试图自己寻找解释,但无济于事。它显然是在尝试对数据库运行该语句,但它应该理解“lastcontact”是作为函数参数给出的变量。

【问题讨论】:

    标签: sql postgresql null dynamic-sql plpgsql


    【解决方案1】:

    从 cmets 中我终于明白了。你需要dynamic SQL:

    CREATE OR REPLACE FUNCTION foo(lastcontact timestamptz)
      RETURNS void AS
    $func$
    DECLARE
       myrec  record;
       mycond boolean;
    BEGIN
    
    FOR myrec IN
        SELECT * FROM tabel ORDER BY colorlevel, volgnummer
    LOOP
        IF myrec.conditie ~~ '%lastcontact %' THEN   -- special case for input param
            myrec.conditie := replace (myrec.conditie
                            , 'lastcontact '
                            , CASE WHEN lastcontact IS NULL THEN 'NULL '
                              ELSE '''' || lastcontact::text || ''' ' END);
        END IF;
    
        EXECUTE 'SELECT ' || myrec.conditie || ' FROM tabel' INTO mycond;
    
        IF mycond then
            RAISE NOTICE 'Condition % is true', myrec.conditie;
        ELSE
            RAISE NOTICE 'Condition % is false', COALESCE(myrec.conditie, 'NULL');
        END IF;
    END LOOP;
    
    END
    $func$  LANGUAGE plpgsql;
    

    但是请注意,此设置对于 SQL 注入 是开放的。仅使用经过验证的输入。 一个函数也可以在 PostgreSQL 8.3 中工作(目前还没有 DO 语句)。

    您不能在动态 SQL(EXECUTE 语句)中引用参数。您必须将值放入查询字符串中。

    在 PostgreSQL 8.4 或更高版本中,您拥有 USING clause 的优越商品。唉,不在 8.3 版中。如果可以,您应该考虑升级。

    我为您的旧版本提供了一种解决方法。您必须特别注意NULL 值。

    【讨论】:

    • 这不是一个表定义,但它显示了三个示例行。如果“conditie”字段包含“lastcontact
    • 该字段的类型为boolean,正如错误消息告诉我们的那样。所以它可以包含NULLTRUEFALSE。没有别的,尤其是字符串'lastcontact < now()'。您尝试在boolean 列中输入一个字符串。不可能。
    • 该列是一个字符串。我得到了字符串,它应该给我一个TRUEFALSE。该字符串包含一个条件。如果我在代码中说“if lastcontact TRUE 或FALSE。我想替换代码,因此只需更改表中的记录即可更改条件。我希望你理解这个问题,我想你没有理解它,我的问题可能不是那么清楚。
    • @Leonard 我想我现在明白你的问题了。请参阅修改后的答案。
    • 这次你确实明白我的问题了:)。您的回答可能令人满意,但我使用的是 8.3 版,并且代码是更大功能的一部分。两个问题:1)我可以在版本 8.3 中使用它吗? 2)DO $$ 和 $$ 之间应该是什么?我的第一次尝试导致错误syntax error at or near "DO"。只有DECLARE ... BEGIN FOR myrec IN ... LOOP ... END LOOP ... END 在双美元之间。
    猜你喜欢
    • 1970-01-01
    • 2013-02-26
    • 2016-12-12
    • 1970-01-01
    • 2013-04-01
    • 2018-11-25
    • 2014-03-02
    • 2017-10-09
    • 1970-01-01
    相关资源
    最近更新 更多