PostgreSQL - 具有局部变量的函数 - 列引用不明确
PostgreSQL - Function with local variables - Column reference is ambiguous
我已经查看了与我的主题相匹配的其他问题,但在我的例子中,我认为歧义来自与列同名的变量。
这是我尝试创建的函数的简化版本:
CREATE OR REPLACE FUNCTION get_user_id(username TEXT)
RETURNS INTEGER AS $$
DECLARE
user_id BIGINT;
other_param TEXT;
BEGIN
SELECT INTO user_id user_id FROM users WHERE users.username = get_user_id.username;
SELECT INTO other_param users.value FROM users WHERE users.user_id = user_id;
RETURN user_id;
END
$$ LANGUAGE PLPGSQL
问题在于 WHERE
右侧的 user_id
被视为对该列的引用。
我肯定需要在局部变量中使用 user_id
,因为它将在函数的 UPDATE
和 DELETE
操作中进一步使用,但我不会将其传递为一个参数,只有用户名。
经过一些阅读并且之前也遇到过一些参数问题,我意识到我可以使用 get_user_id.username
但它只适用于参数,而不适用于局部变量(如果我将它与变量一起使用,查询会失败,因为那里不是 get_user_id
的 FROM 子句)。
因此,关于在函数内的查询中使用变量,我是否遗漏了一些(不那么)明显的东西?
--- 编辑
抱歉我过度简化了函数,当然有第一个查询获取 user_id,那部分工作正常。
是不是漏了用户名过滤?我想你想要这样的东西:
SELECT users.user_id INTO user_id FROM users WHERE users.username = username;
这样的话,users.user_id
的值会在用户名过滤后设置在user_id
变量中。
我给参数和变量加上前缀,这样它们就不太可能与列名冲突:
CREATE OR REPLACE FUNCTION get_user_id (in_username TEXT)
RETURNS INTEGER AS $$
DECLARE
v_user_id BIGINT;
BEGIN
SELECT u.user_id INTO v_user_id FROM users u WHERE u.user_id = in_user_id;
RETURN v_user_id;
END
$$ LANGUAGE PLPGSQL
不过,您可能想比较用户名:
SELECT u.user_id INTO v_user_id FROM users u WHERE u.username = in_username;
https://www.postgresql.org/docs/current/static/plpgsql-implementation.html
Sometimes it is impractical to fix all the ambiguous references in a
large body of PL/pgSQL code. In such cases you can specify that
PL/pgSQL should resolve ambiguous references as the variable
等等...因此:
t=# CREATE OR REPLACE FUNCTION get_user_id(username TEXT)
RETURNS INTEGER AS $$
#variable_conflict use_variable
DECLARE
user_id BIGINT;
other_param TEXT;
BEGIN
SELECT INTO user_id users.user_id FROM users WHERE users.username = username;
RETURN user_id;
END
$$ LANGUAGE PLPGSQL
;
CREATE FUNCTION
让我们检查一下:
t=# create table users (user_id int, username text);
CREATE TABLE
t=# insert into users values (1,'a');
INSERT 0 1
t=# select get_user_id('a');
get_user_id
-------------
1
(1 row)
注意 - 这个检查有很大的意义,如果你禁用它,你会得到一些非常丑陋和非常不可见的错误。这很危险。请不要这样做。
不要使用它,除非你看到不可见的错误或者你控制每一行
任何局部变量都可以由块标签限定
create table foo(a integer);
insert into foo values(10);
do $$
<<mylabel>>
declare
a int default 5;
r record;
begin
select foo.a into r
from foo
where foo.a = mylabel.a + 5;
raise notice '%', r.a;
end;
$$;
NOTICE: 10
DO
通常所有可能发生冲突的局部变量都有前缀——常见的前缀是_
.
我已经查看了与我的主题相匹配的其他问题,但在我的例子中,我认为歧义来自与列同名的变量。
这是我尝试创建的函数的简化版本:
CREATE OR REPLACE FUNCTION get_user_id(username TEXT)
RETURNS INTEGER AS $$
DECLARE
user_id BIGINT;
other_param TEXT;
BEGIN
SELECT INTO user_id user_id FROM users WHERE users.username = get_user_id.username;
SELECT INTO other_param users.value FROM users WHERE users.user_id = user_id;
RETURN user_id;
END
$$ LANGUAGE PLPGSQL
问题在于 WHERE
右侧的 user_id
被视为对该列的引用。
我肯定需要在局部变量中使用 user_id
,因为它将在函数的 UPDATE
和 DELETE
操作中进一步使用,但我不会将其传递为一个参数,只有用户名。
经过一些阅读并且之前也遇到过一些参数问题,我意识到我可以使用 get_user_id.username
但它只适用于参数,而不适用于局部变量(如果我将它与变量一起使用,查询会失败,因为那里不是 get_user_id
的 FROM 子句)。
因此,关于在函数内的查询中使用变量,我是否遗漏了一些(不那么)明显的东西?
--- 编辑
抱歉我过度简化了函数,当然有第一个查询获取 user_id,那部分工作正常。
是不是漏了用户名过滤?我想你想要这样的东西:
SELECT users.user_id INTO user_id FROM users WHERE users.username = username;
这样的话,users.user_id
的值会在用户名过滤后设置在user_id
变量中。
我给参数和变量加上前缀,这样它们就不太可能与列名冲突:
CREATE OR REPLACE FUNCTION get_user_id (in_username TEXT)
RETURNS INTEGER AS $$
DECLARE
v_user_id BIGINT;
BEGIN
SELECT u.user_id INTO v_user_id FROM users u WHERE u.user_id = in_user_id;
RETURN v_user_id;
END
$$ LANGUAGE PLPGSQL
不过,您可能想比较用户名:
SELECT u.user_id INTO v_user_id FROM users u WHERE u.username = in_username;
https://www.postgresql.org/docs/current/static/plpgsql-implementation.html
Sometimes it is impractical to fix all the ambiguous references in a large body of PL/pgSQL code. In such cases you can specify that PL/pgSQL should resolve ambiguous references as the variable
等等...因此:
t=# CREATE OR REPLACE FUNCTION get_user_id(username TEXT)
RETURNS INTEGER AS $$
#variable_conflict use_variable
DECLARE
user_id BIGINT;
other_param TEXT;
BEGIN
SELECT INTO user_id users.user_id FROM users WHERE users.username = username;
RETURN user_id;
END
$$ LANGUAGE PLPGSQL
;
CREATE FUNCTION
让我们检查一下:
t=# create table users (user_id int, username text);
CREATE TABLE
t=# insert into users values (1,'a');
INSERT 0 1
t=# select get_user_id('a');
get_user_id
-------------
1
(1 row)
注意 - 这个检查有很大的意义,如果你禁用它,你会得到一些非常丑陋和非常不可见的错误。这很危险。请不要这样做。
不要使用它,除非你看到不可见的错误或者你控制每一行
任何局部变量都可以由块标签限定
create table foo(a integer);
insert into foo values(10);
do $$
<<mylabel>>
declare
a int default 5;
r record;
begin
select foo.a into r
from foo
where foo.a = mylabel.a + 5;
raise notice '%', r.a;
end;
$$;
NOTICE: 10
DO
通常所有可能发生冲突的局部变量都有前缀——常见的前缀是_
.