1

我在 PostgreSQL 中有一个存储过程

CREATE OR REPLACE FUNCTION show_senti_lang_setting(IN _senti_id bigint)
RETURNS TABLE(lang_code character, native_name character varying, is_active boolean) AS
$BODY$
BEGIN
RETURN QUERY 
    SELECT
        l.lang_code,
        l.native_name,
        (CASE WHEN s.senti_id is NULL THEN FALSE
            ELSE TRUE
        END) is_active
    FROM
        language l
    LEFT JOIN senti_lang s
    ON s.lang_code=l.lang_code
    AND s.senti_id=_senti_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE STRICT;

错误是:

ERROR:  syntax error at or near "$1"
LINE 1: ...HEN s.senti_id is NULL THEN FALSE ELSE TRUE END)  $1  FROM l...
                                                         ^
QUERY:   SELECT l.lang_code, l.native_name, (CASE WHEN s.senti_id is NULL THEN FALSE ELSE TRUE END)  $1  FROM language l LEFT JOIN senti_lang s ON s.lang_code=l.lang_code AND s.senti_id= $2 
CONTEXT:  SQL statement in PL/PgSQL function "show_senti_lang_setting" near line 13

********** Error **********

ERROR: syntax error at or near "$1"
SQL state: 42601
Context: SQL statement in PL/PgSQL function "show_senti_lang_setting" near line 13

似乎错误是由于CASEplpgsql 引起的。相同的函数在 SQL 中运行良好:

CREATE OR REPLACE FUNCTION show_senti_lang_setting(bigint)
    RETURNS TABLE(lang_code character, native_name character varying, is_active boolean) AS
$BODY$

    SELECT
        l.lang_code,
        l.native_name,
        CASE WHEN s.senti_id is NULL THEN FALSE
            ELSE TRUE
        END is_active
    FROM
        language l
    LEFT JOIN senti_lang s
    ON s.lang_code=l.lang_code
    AND s.senti_id=$1;

$BODY$
  LANGUAGE sql VOLATILE STRICT;
4

2 回答 2

6

至于你有什么:

8.4 版在返回的行 ( )OUT中存在与列别名同名的参数的问题。is_active这已经被修改了,它适用于 PostgreSQL 9.1 或更高版本(甚至可能是 9.0)。这就是您的语法错误的原因。

列别名只是这个星座中的噪音。它们被丢弃以支持声明的OUT参数。他们唯一的目的可能是文档,所以只需将其作为注释并避免冲突:

    CASE WHEN s.senti_id is NULL THEN FALSE ELSE TRUE END -- AS is_active

还:

  • 您应该将关键字AS与列别名一起使用(而对于表别名,通常可以跳过它)。
  • CASE语句周围不需要括号。

更好的形式

按照您的方式,您始终返回表中的所有行language- 以及找到匹配项的一个或多个实例senti_lang。同时您定义了您的函数STRICT,因此当您为_senti_id. 很难想象一个合理的用例。

如果在senti_lang. 所以你可以简化为:

CREATE OR REPLACE FUNCTION show_senti_lang_setting(IN _senti_id bigint)
RETURNS TABLE(lang_code character, native_name varchar, is_active boolean) AS
$func$
BEGIN
RETURN QUERY 
   SELECT l.lang_code
         ,l.native_name
         ,EXISTS (SELECT 1 FROM senti_lang s
                  WHERE  s.lang_code = l.lang_code
                  AND    s.senti_id = _senti_id) -- AS is_active
   FROM   language l;
END
$func$ LANGUAGE plpgsql VOLATILE STRICT;

我会提出是否需要这样的问题STRICT

的意思Select 1

在下面的评论中回复后续问题。我引用手册EXISTS

由于结果仅取决于是否返回任何行,而不取决于这些行的内容,因此子查询的输出列表通常不重要。一个常见的编码约定是以 EXISTS(SELECT 1 WHERE ...) 的形式编写所有 EXISTS 测试。

基本上,您可以编写任何语法上有效的表达式。无论如何它都会被丢弃。
我们一直在这个相关问题下讨论可读性。

于 2013-01-05T14:58:01.723 回答
1

这似乎是参数和case.

如果您在选择查询中重命名别名,它应该可以工作

SELECT
    l.lang_code,
    l.native_name,
    (CASE WHEN s.senti_id is NULL THEN FALSE
        ELSE TRUE
    END) as active_flag  -- <### this is the change 
FROM
    language l
LEFT JOIN senti_lang s
ON s.lang_code=l.lang_code
AND s.senti_id=_senti_id;

SQLFiddle 示例:http ://sqlfiddle.com/#!11/49075/1

case 表达式的值由位置映射到“输出”参数。所以他们可以有不同的名字(显然必须)。

于 2013-01-05T13:48:33.923 回答