我在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
似乎错误是由plpgsql中的CASE
引起的。相同的函数在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;
答案 0 :(得分: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
提供NULL值时,根本不会获得任何行。很难想象一个明智的用例。
如果在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
在下面的评论中回答后续问题。我引用the manual on EXISTS
:
因为结果仅取决于是否返回任何行,并且 不在这些行的内容上,子查询的输出列表是 通常不重要。一种常见的编码约定是全写 以EXISTS(SELECT 1 WHERE ...)的形式进行EXISTS测试。
基本上你可以编写任何语法上有效的表达式。无论如何它都被丢弃了 我们一直在讨论this related question下的可读性。
答案 1 :(得分: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表达式的值由位置映射到“output”参数。所以他们可以有不同的名字(显然必须)。