Reputation: 2879
I have had a look at other questions that match my subject but in my case the ambiguity, I believe, comes from variable having the same name as a column.
Here is a simplified version of the function I am trying to create:
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
The problem is that the user_id
on the right hand side of the WHERE
is treated as a reference to the column.
I definitely need user_id
in a local variable as it will be used in UPDATE
and DELETE
operations further along the function, but I won't get the it passed as a parameter, only username.
Upon some reading and having previously had some problems with parameters too I realised I can use get_user_id.username
but it only applies to parameters, not local variables (if I use it with variable the query with fail as there is not FROM-clause for get_user_id
).
Therefore am I missing something (not so) obvious about using variables in queries inside a function?
--- edit
Apologies I oversimplified the function, of course there's a first query that gets the user_id, and that part is working fine.
Upvotes: 6
Views: 5098
Reputation: 51659
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
and so on... thus:
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
let's check:
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)
Attention - this check has big sense, and if you disable it, you can get some very ugly and very invisible errors. This is pretty dangerous. Don't do it, please.
Don't use it, unless you see invisible errors or you hold EVERY line under control
Upvotes: 3
Reputation: 45950
Any local variable can be qualified by block label
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
Usually all possible conflict local variables has prefix - common prefix is _
.
Upvotes: 8
Reputation: 1271211
I prefix parameters and variables so they are less likely to conflict with column names:
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
Presumably, though, you want to compare user names:
SELECT u.user_id INTO v_user_id FROM users u WHERE u.username = in_username;
Upvotes: 7
Reputation: 201
It is not missing username filtering? I think you wanted something like:
SELECT users.user_id INTO user_id FROM users WHERE users.username = username;
Is that way, the value of users.user_id
will be set in user_id
variable after a username filtering.
Upvotes: 0