用户定义函数中的 PostgreSQL EXISTS 总是返回 true
PostgreSQL EXISTS in user-defined function always returning true
我编写了一个简单的用户定义函数来检查是否存在符合某些条件的行:
CREATE OR REPLACE FUNCTION is_instructor_specialized_in(eid INT, course_area VARCHAR(50))
RETURNS BOOLEAN AS $$
SELECT EXISTS(SELECT 1 FROM Specializes s WHERE s.eid = eid AND s.name = course_area);
$$ LANGUAGE sql;
我使用以下查询对其进行了测试:
SELECT is_instructor_specialized_in(2, 'Artificial Intelligence') as function_output,
EXISTS(SELECT 1 FROM Specializes s WHERE s.eid = 2 AND s.name = 'Artificial Intelligence') as ground_truth;
并且该函数给出了一个错误的值 true
当它应该计算为 false
时(Specializes
table 中没有这样的行):
image
其实总是给出true
的值。我超级困惑。发生这种情况有什么原因吗?
版本:x86_64-apple-darwin19.6.0 上的 PostgreSQL 13.2,由 Apple clang 版本 11.0.3 (clang-1103.0.32.62) 编译,64 位
就像@wildplasser 暗示的那样,您的函数参数 eid
与 table 列同名,即 never 好主意。在这种情况下,它默默地破坏了你的功能。
WHERE s.eid = eid
中的非限定 eid
解析为 table 列,而不是函数参数,正如您所期望的那样。因此,对于任何非空输入,此谓词的计算结果为 true
。偷偷摸摸的错误。
If the argument name is the same as any column name in the current SQL
command within the function, the column name will take precedence. To
override this, qualify the argument name with the name of the function
itself, that is function_name.argument_name
. (If this would
conflict with a qualified column name, again the column name wins. You
can avoid the ambiguity by choosing a different alias for the table
within the SQL command.)
大胆强调我的。
用函数名限定是不得已的尴尬措施。避免以明确的参数名称开头的问题。一种约定是在参数前加上下划线 (_
) - 永远不要对 table 列做同样的事情:
CREATE OR REPLACE FUNCTION func_proper(_eid int, _course_area text)
RETURNS boolean
LANGUAGE sql STABLE PARALLEL SAFE AS
$func$
SELECT EXISTS(SELECT FROM specializes s WHERE s.eid = _eid AND s.name = _course_area);
$func$;
或者对像您这样的简单案例使用位置 $n
参数引用。您仍然可以为文档和命名函数调用使用参数名称:
CREATE OR REPLACE FUNCTION func_proper(_eid int, _course_area text)
RETURNS boolean
LANGUAGE sql STABLE PARALLEL SAFE AS
$func$
SELECT EXISTS(SELECT FROM specializes s WHERE s.eid = AND s.name = );
$func$;
db<>fiddle here
PL/pgSQL 函数中相同命名冲突的默认行为是引发异常,顺便说一下。参见:
- Naming conflict between function parameter and result of JOIN with USING clause
- PL/pgSQL column name the same as variable
我编写了一个简单的用户定义函数来检查是否存在符合某些条件的行:
CREATE OR REPLACE FUNCTION is_instructor_specialized_in(eid INT, course_area VARCHAR(50))
RETURNS BOOLEAN AS $$
SELECT EXISTS(SELECT 1 FROM Specializes s WHERE s.eid = eid AND s.name = course_area);
$$ LANGUAGE sql;
我使用以下查询对其进行了测试:
SELECT is_instructor_specialized_in(2, 'Artificial Intelligence') as function_output,
EXISTS(SELECT 1 FROM Specializes s WHERE s.eid = 2 AND s.name = 'Artificial Intelligence') as ground_truth;
并且该函数给出了一个错误的值 true
当它应该计算为 false
时(Specializes
table 中没有这样的行):
image
其实总是给出true
的值。我超级困惑。发生这种情况有什么原因吗?
版本:x86_64-apple-darwin19.6.0 上的 PostgreSQL 13.2,由 Apple clang 版本 11.0.3 (clang-1103.0.32.62) 编译,64 位
就像@wildplasser 暗示的那样,您的函数参数 eid
与 table 列同名,即 never 好主意。在这种情况下,它默默地破坏了你的功能。
WHERE s.eid = eid
中的非限定 eid
解析为 table 列,而不是函数参数,正如您所期望的那样。因此,对于任何非空输入,此谓词的计算结果为 true
。偷偷摸摸的错误。
If the argument name is the same as any column name in the current SQL command within the function, the column name will take precedence. To override this, qualify the argument name with the name of the function itself, that is
function_name.argument_name
. (If this would conflict with a qualified column name, again the column name wins. You can avoid the ambiguity by choosing a different alias for the table within the SQL command.)
大胆强调我的。
用函数名限定是不得已的尴尬措施。避免以明确的参数名称开头的问题。一种约定是在参数前加上下划线 (_
) - 永远不要对 table 列做同样的事情:
CREATE OR REPLACE FUNCTION func_proper(_eid int, _course_area text)
RETURNS boolean
LANGUAGE sql STABLE PARALLEL SAFE AS
$func$
SELECT EXISTS(SELECT FROM specializes s WHERE s.eid = _eid AND s.name = _course_area);
$func$;
或者对像您这样的简单案例使用位置 $n
参数引用。您仍然可以为文档和命名函数调用使用参数名称:
CREATE OR REPLACE FUNCTION func_proper(_eid int, _course_area text)
RETURNS boolean
LANGUAGE sql STABLE PARALLEL SAFE AS
$func$
SELECT EXISTS(SELECT FROM specializes s WHERE s.eid = AND s.name = );
$func$;
db<>fiddle here
PL/pgSQL 函数中相同命名冲突的默认行为是引发异常,顺便说一下。参见:
- Naming conflict between function parameter and result of JOIN with USING clause
- PL/pgSQL column name the same as variable