return a value from insert stored procedure (not function)? - postgresql

I'm new for postgresql and getting ERROR while calling stored procedure in postgresql:
ERROR: column reference "id" is ambiguous. LINE 5: (id,isactive,createddatetime, fullname) RETURNING id
create or REPLACE procedure increase(
inout id character varying(50),
in isactive boolean,
in createddatetime DATE,
in fullname text
)
LANGUAGE 'plpgsql'
AS $$
begin
INSERT INTO
public.contactus
(id,isactive,createddatetime, fullname)
VALUES
(id,isactive,createddatetime, fullname) RETURNING id into id;
end ;
$$;
CALL increase('Test001',true,'1997-10-01','ok msg')
Please provide the example in same format. So, it will good for understating me and others.

The function parameters have the same name as the table columns. That constitutes an ambiguity. Avoid that by either choosing different parameter names or by qualifying the parameters with the function name in the SQL statement: increase.id.

I'm adding this example that help to other.
create or REPLACE procedure increase(
inout id character varying(50),
in isactive boolean,
in createddatetime DATE,
in fullname text
)
LANGUAGE 'plpgsql'
AS $$
begin
INSERT INTO
public.contactus
(id,isactive,createddatetime, fullname)
VALUES
(id,isactive,createddatetime, fullname) RETURNING increase.id into id;
end ;
$$;
CALL increase('Test001',true,'1997-10-01','1997-10-21','ok msg')

Related

Using parameter as column name in Postgres function

I have a Postgres table bearing the following form
CREATE TABLE "public"."days"
(
"id" integer NOT NULL,
"day" character varying(9) NOT NULL,
"visits" bigint[] NOT NULL,
"passes" bigint[] NOT NULL
);
I would like to write a function that allows me to return the visits or the passees column as its result for a specified id. My first attempt goes as follows
CREATE OR REPLACE FUNCTION day_entries(INT,TEXT) RETURNS BIGINT[] LANGUAGE sql AS
'SELECT $2 FROM days WHERE id = $1;'
which fails with an error along the lines of
return type mismatch in function declared to return bigint[]
DETAIL: Actual return type is text.
If I put in visits in place of the $2 things work just as expected. It would make little sense to define several functions to match different columns from the days table. Is there a way to pass the actual column name as a parameter while still keeping Postgres happy?
You can't use parameters as identifiers (=column name), you need dynamic SQL for that. And that requires PL/pgSQL:
CREATE OR REPLACE FUNCTION day_entries(p_id int, p_column text)
RETURNS BIGINT[]
AS
$$
declare
l_result bigint[];
begin
execute format('SELECT %I FROM days WHERE id = $1', p_column)
using p_id
into l_result;
return l_result;
end;
$$
LANGUAGE plpgsql;
format() properly deals with identifiers when building dynamic SQL. The $1 is a parameter placeholder and the value for that is passed with the using p_id clause of the execute statement.

SELECT in INSERTING in postgreSQL

I have two table Documents and RegCard (name uses a name of current_user)
Table Documents
CREATE TABLE public.document_dimauser
(
documentid uuid NOT NULL,
documentname character varying(100),
author character varying(100),
contents bytea,
CONSTRAINT document_dimauser_pkey PRIMARY KEY (documentid)
)
Table RegCard
CREATE TABLE public.regcard_dimauser
(
regcardid uuid NOT NULL,
documentid uuid,
documentintronumber character varying(100),
documentexternnumber character varying(100),
dateintro date,
dateextern date,
CONSTRAINT regcard_dimauser_pkey PRIMARY KEY (regcardid),
CONSTRAINT regcard_dimauser_documentid_fkey FOREIGN KEY (documentid)
REFERENCES public.document_dimauser (documentid) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
This two tables are connected one row 'documentid'
Also, i have a function, which inserting data in this two tables. Here i try selecting last rec of documentid from first table and transer him in second table
CREATE OR REPLACE FUNCTION public.addrecuserdocuments(
documentname character varying,
contents bytea,
documentintronumber character varying)
RETURNS void AS
$BODY$
DECLARE
comm VARCHAR;
nameuser VARCHAR;
currdate DATE;
iddoc uuid;
BEGIN
SELECT CURRENT_USER INTO STRICT nameuser;
SELECT CURRENT_DATE INTO STRICT currdate;
comm:='INSERT INTO Document_'||nameuser||' VALUES ('||quote_literal(uuid_generate_v4())||', '||quote_literal(documentname)||','||quote_literal(nameuser)||','||quote_literal(contents)||');
SELECT documentid INTO STRICT '||quote_literal(iddoc)||' FROM Document_'||nameuser||' order by documentid DESC LIMIT 1;
INSERT INTO Regcard_'||nameuser||' (regcardid, documentid, documentintronumber, dateintro) VALUES ('||quote_literal(uuid_generate_v4())||' , '||quote_literal(iddoc)||', '||quote_literal(documentintronumber)||', '||quote_literal(currdate)||');';
EXECUTE comm;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
But i have a error
ERROR: query string argument of EXECUTE is null
SQL-состояние: 22004
Контекст: PL/pgSQL function addrecuserdocuments(character varying,bytea,character varying) line 13 at EXECUTE
Please, tell me, what i do wrong?
you concat with || operator - if any value is null the whole string is null...
you can instead do smth like :
comm := format('INSERT INTO %I VALUES(%L)',concat(Document_',nameuser),uuid_generate_v4());
and so on...
Don't concatenate input values if you don't need that, use parameters in the string and use format() to build it. You also don't need variables to store the results of built-in functions and you don't need to "select" the UUID you generated inside your code.
Putting all that together you can simplify your code to:
BEGIN
iddoc := uuid_generate_v4();
comm : = format('INSERT INTO Document_%s VALUES ($1, $2, $3, $4)', current_user);
execute comm
using iddoc, documentname, current_user, contents;
comm := format('insert into regcard_%s (regcardid, documentid, documentintronumber, dateintro) values ($1, $2, $3, $4)', current_user);
execute comm
using uuid_generate_v4(), iddoc, documentintronumber, current_date;
END;
This not only makes the code much more readable it is also a way to prevent SQL injection through that function.
Unrelated, but: I find a design that uses a table with the user name appended highly questionable - especially if that user name is also stored inside the table. If you don't do that you can avoid all that dynamic SQL.

Rename the column name of a stored function

I've got a postgresql stored procedure, which is returning an integer.
When I call that function, the result is returned with the function name as column name.
For example the name of the function is: "add-person". The column name, when invoking the function, is "add-person".
Is there a way to make the database return the integer with a self-choosen column name? For example "id"?
I think it is pretty easy, but I currently miss the forests for the trees..
Edit:
What i'd missed to tell, is that the return value is a variable, like so:
CREATE OR REPLACE FUNCTION "scheme"."add-person"(arggivenname character varying, argfamilyname character varying) RETURNS integer AS
$BODY$
DECLARE
varResponse integer;
BEGIN
-- Operations before
INSERT INTO "scheme"."table"
(
given_name,
family_name
)
VALUES
(
arggivenname,
argfamilyname
)
RETURNING
"id"
INTO
varResponse;
-- Operations after
RETURN varResponse;
END;
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;
You can us the AS statement for that. That means:
Select add-person() AS yourcolumnname
To have a named column from a function it is necessary to create a type and return that type from the function
create type mytype as (mycolumn integer);
create or replace function ri()
returns mytype as $$
select 1;
$$ language sql;
select * from ri();
mycolumn
----------
1
Edit
Or much simpler without the type creation as in #pozs comment:
create or replace function ri(out mycolumn integer)
as $$
select 1;
$$ language sql;

Pass UUID value as a parameter to the function

I have the table with some columns:
--table
create table testz
(
ID uuid,
name text
);
Note: I want to insert ID values by passing as a parameter to the function. Because I am generating the ID value
in the front end by using uuid_generate_v4(). So I need to pass the generated value to the function to insert
into the table
My bad try:
--function
CREATE OR REPLACE FUNCTION testz
(
p_id varchar(50),
p_name text
)
RETURNS VOID AS
$BODY$
BEGIN
INSERT INTO testz values(p_id,p_name);
END;
$BODY$
LANGUAGE PLPGSQL;
--EXECUTE FUNCTION
SELECT testz('24f9aa53-e15c-4813-8ec3-ede1495e05f1','Abc');
Getting an error:
ERROR: column "id" is of type uuid but expression is of type character varying
LINE 1: INSERT INTO testz values(p_id,p_name)
You need a simple cast to make sure PostgreSQL understands, what you want to insert:
INSERT INTO testz values(p_id::uuid, p_name); -- or: CAST(p_id AS uuid)
Or (preferably) you need a function, with exact parameter types, like:
CREATE OR REPLACE FUNCTION testz(p_id uuid, p_name text)
RETURNS VOID AS
$BODY$
BEGIN
INSERT INTO testz values(p_id, p_name);
END;
$BODY$
LANGUAGE PLPGSQL;
With this, a cast may be needed at the calling side (but PostgreSQL usually do better automatic casts with function arguments than inside INSERT statements).
SQLFiddle
If your function is that simple, you can use SQL functions too:
CREATE OR REPLACE FUNCTION testz(uuid, text) RETURNS VOID
LANGUAGE SQL AS 'INSERT INTO testz values($1, $2)';

ERROR: input parameters after one with a default value must also have defaults in Postgres

I am trying to set default value to a variable within the function in parameter list but getting an error:
ERROR: input parameters after one with a default value must also have defaults
Example:
Create or replace function test(name varchar default null
, city varchar default null
, phonenumber varchar(20) default null
, out sno bigint, address varchar)
returns void as
$$
Declare
phonenumber AS VarChar(20);
Begin
phonenumber : =phonenumber;
SELECT sno = MAX(ssno)+1 FROM emp;
IF(sno IS NULL) then
sno=IDENT_CURRENT('emp')+1;
end;
raise info '%',name;
raise info '%',city;
raise info '%',phonenumber;
raise info '%',address;
insert into emp(ename,ecity,ephonenumber,eaddress)
values(name,city,phonenumber,address);
end;
$$
langauge plpgsql;
Much is not right in your example. Or rather: not much is right in your example.
CREATE OR REPLACE FUNCTION f_test(
name text = NULL
, city text = NULL
, phonenumber text = NULL
,address text = NULL
, OUT sno bigint)
RETURNS void AS
$func$
DECLARE
phonenumber AS VarChar(20); -- would collide with parameter name
BEGIN
phonenumber := phonenumber; -- nonsense
SELECT INTO sno max(ssno) + 1 FROM emp; -- SELECT INTO for assignment
IF sno IS NULL THEN
sno := ident_current('emp') + 1;
END IF;
RAISE NOTICE '%, %, %, %', name, city, phonenumber, address;
INSERT INTO emp(ename, ecity, ephonenumber, eaddress)
VALUES (name, city, phonenumber, address);
END
$func$ LANGUAGE plpgsql;
Major points
The error message speaks for itself:
input parameters after one with a default value must also have defaults.
That's almost what the manual has on that:
All input parameters following a parameter with a default value must
have default values as well.
It wouldn't make sense to combine RETURNS void with OUT parameters.
Don't declare variable names colliding with parameter names. Completely useless here.
The plpgsql assignment operator is :=, not =.
You don't normally use the RAISE level INFO. You want NOTICE instead.
SELECT without target is not possible in plpgsql, you want SELECT INTO.
IF is terminated with END IF not with END.
Simplify further
Use COALESCE to replace your IF statement. Aggregate functions return a row even if the table is empty.
But you don't need that either. Just use the RETURNING clause to return the new id directly:
CREATE OR REPLACE FUNCTION f_test(
name text = NULL
, city text = NULL
, phonenumber text = NULL
, address text = NULL
, OUT sno bigint)
AS
$func$
BEGIN
RAISE NOTICE '%, %, %, %', name, city, phonenumber, address;
INSERT INTO emp(ename, ecity, ephonenumber, eaddress)
VALUES (name, city, phonenumber, address)
RETURNING ssno
INTO sno; -- Assuming you want to return autoincremented id
END
$func$ LANGUAGE plpgsql;
Try
Create or replace function test(
out sno bigint,
address varchar,
name varchar default null,
city varchar default null,
phonenumber varchar(20) default null)
returns void as ..
Here you just need to reorder just it. In that case your problem will solved. default field must be at bottom.
Create or replace function test(
out sno bigint,
,address varchar
,name varchar default null
,city varchar default null
,phonenumber varchar(20) default null
)