How to insert a parameter value in insert query in PostgreSQL function? - function

I wrote a function in PostgreSQL with a parameter, where I want to insert the parameter value in a database table. The script executes fine but when I call the function I got an error message:
CREATE OR REPLACE FUNCTION sp_load_purchase_order(x int)
RETURNS void AS
$$
declare var_val char;
begin
var_val='p'+i;
insert into purchase_order(
create_uid,
create_date,
write_date,
write_uid,
journal_id,
date_order,
partner_id,
amount_untaxed,
location_id,
company_id,
amount_tax,
state,
pricelist_id,
warehouse_id,
payment_term_id,
amount_total,
name,
invoice_method,
shipped,
minimum_planned_date
)
values(1,now(),now(),1,13,now(),17,1.00,12,1,0.00,'draft',2,1,3,1.00
,var_val,'order','f' ,now()
);
end;
$$
LANGUAGE 'plpgsql';
Error message:
ERROR: column "i" does not exist
LINE 1: SELECT 'p'+i
^
QUERY: SELECT 'p'+i
CONTEXT: PL/pgSQL function sp_load_purchase_order(integer) line 5 at assignment
********** Error **********
ERROR: column "i" does not exist
SQL state: 42703
Context: PL/pgSQL function sp_load_purchase_order(integer) line 5 at assignment
Please help me point out the problem.

And the assignment operator in plpgsql is :=:
The forgotten assignment operator "=" and the commonplace ":="
And do not quote the language name plpgsql!
And you do not need to declare a variable for that. The concatenation can take place in the INSERT statement, which is cheaper.
CREATE OR REPLACE FUNCTION sp_load_purchase_order(x int)
RETURNS void AS
$func$
begin
insert into purchase_order(create_uid, ..., name, ...)
values(1, ..., 'p' || x, ...);
end
$func$ LANGUAGE plpgsql;

Your function parameter is named x but your function body refers to an undeclared variable named i...

I've done two bad mistakes in my script... one was that undeclared 'i' variable, and another one was my concatenating attempt where i used '+' sign... here is the working code::::
CREATE OR REPLACE FUNCTION sp_load_purchase_order(x int)
RETURNS void AS
$$
declare var_val char(10);
begin
var_val='p'||x;
insert into purchase_order(
create_uid,
create_date,
write_date,
write_uid,
journal_id,
date_order,
partner_id,
amount_untaxed,
location_id,
company_id,
amount_tax,
state,
pricelist_id,
warehouse_id,
payment_term_id,
amount_total,
name,
invoice_method,
shipped,
minimum_planned_date
)
values(
1,now(),now(),1,13,now(),17,1.00,12,1,0.00,'draft',2,1,3,1.00,var_val,'order','f' ,now()
);
end;
$$
LANGUAGE 'plpgsql';

Related

Why Mysql always returns zero value withing stored procedure?

I use following to reserve id if not exist in table;
CREATE DEFINER=`root`#`localhost` PROCEDURE `get_ch_id_from_ych_id`(pYch_id nvarchar(100), pIP_address nvarchar(30))
BEGIN
declare ch_id bigint;
set ch_id =(select ifnull(max(ch_id),0)ch_id from channels where ych_id=pYch_id);
if(ch_id<1) then
INSERT INTO channels
(ych_id, Name, Last_IP, Active, Banned, Qualified, ReportedCount)
VALUES
(pYch_id,Name,pIP_address,1 ,0 ,0 ,0);
end if;
select ifnull(max(ch_id),0) ch_id from channels where ych_id=pYch_id;
END
However, it always return zero when called as below;
call get_ch_id_from_ych_id ('A',''); //not work
select ifnull(max(ch_id),0) ch_id from channels where ych_id='A'; //works
Data row is inserted without problem and exist in table. but in first line,
it returns zero. when I run sql in workbench it returns correct value. What is wrong here?
Don't give you local variable the same name as a table column. When you refer to ch_id in the query, it uses the variable rather than the column.
CREATE DEFINER=`root`#`localhost` PROCEDURE `get_ch_id_from_ych_id`(pYch_id nvarchar(100), pIP_address nvarchar(30))
BEGIN
declare temp_ch_id bigint;
set temp_ch_id =(select ifnull(max(ch_id),0)ch_id from channels where ych_id=pYch_id);
if(temp_ch_id<1) then
INSERT INTO channels
(ych_id, Name, Last_IP, Active, Banned, Qualified, ReportedCount)
VALUES
(pYch_id,Name,pIP_address,1 ,0 ,0 ,0);
end if;
select ifnull(max(ch_id),0) ch_id from channels where ych_id=pYch_id;
END
I don't think you can so this in MySQL.
You need to convert the stored procedure to a function or use an OUT parameter to return values.
Source: MySQL - Returning Single Value from Stored Procedure

ERROR: cannot cast type integer to json in Postgresql

When I am trying to insert the record in tableA, i am getting the below error:
QUERY: insert into schemaname.tableB(col1, col2) values(....)
CONTEXT: PL/pgSQL function schemaname.funcA() line 5 at SQL statement
********** Error **********
ERROR: cannot cast type integer to json
SQL state: 42846
Context: PL/pgSQL function schemaname.funcA() line 5 at SQL statement
I have created following trigger which function when record gets committed:
CREATE CONSTRAINT TRIGGER trg_name
AFTER INSERT
ON schemaname.tableA
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE schemaname.funcA();
In the below trigger function col1 is of integer type and col2 is of json type.
CREATE OR REPLACE FUNCTION schemaname.funcA()
RETURNS trigger AS
$BODY$
BEGIN
insert into schemaname.tableB(col1, col2) values(NEW.val1, json_build_object("abc", NEW.col2val1::json, "def", NEW.col2val2::json, "ghi", NEW.col2val3::json));
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Could you please help me what could be the cause of this error?
There is no cast from integer to json.
But since json_build_object accepts arguments of any type, you can solve the problem by removing the ::json casts in your trigger function.
By the way, using "abc" as a string constant is wrong – probably an error introduced while trying to obfuscate your code. You have to write '"abc"'.
CREATE OR REPLACE FUNCTION schemaname.funcA() RETURNS trigger AS $BODY$
BEGIN
insert into schemaname.tableB(col1, col2) values(NEW.col1, CAST('{"nameA" : ' ||'"'||NEW.nameA||'", ' || '"nameB" : '||'"'||NEW.nameB||'", ' ||'"nameC" : '||'"'||NEW.nameC||'", ' || '"nameD" : '||'"'||NEW.nameD||'"}' as json));
RETURN NEW;
END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100;

Calling table function from procedure (pl sql)

I am having big trouble calling a function that returns a table from my procedure. I believe there is something wrong with my declaration so its not compiling. Here is my code.. the developer underlines with red the SELECT "D_ID" and from table "(IREL_FN (X))"; . And here is my code.
CREATE OR replace PROCEDURE Irrelevant_skata (x NUMBER)
AS
d_id T_ID_TABLE;
BEGIN
DECLARE
TYPE yo_table
IS
TABLE OF YO_TABLE;
YO_TABLE "(IREL_FN (X))"%TYPE;
id NUMBER;
BEGIN
SELECT "D_ID"
INTO yo_table
FROM TABLE "(IREL_FN (X))";
EXCEPTION
WHEN no_data_found THEN
dbms_output.Put_line('NO DATA FOUND');
END;
END irrelevant_skata;
And the function
CREATE OR replace FUNCTION Irel_fn (x IN NUMBER)
RETURN T_ID_TABLE
AS
id T_ID_TABLE;
BEGIN
BEGIN
SELECT Cast(MULTISET(SELECT "id"
FROM "somethingcopy"
WHERE "kati" IN (SELECT "auto"
FROM "ekeino"
WHERE "id" = x)) AS T_ID_TABLE)
INTO id
FROM dual;
RETURN id;
EXCEPTION
WHEN no_data_found THEN
dbms_output.Put_line('null');
END;
END irel_fn;
It's hard to answer without knowing what you're trying to do.
YO_TABLE "(IREL_FN (X))"%TYPE;
This doesn't make any sense. You can't declare a variable to be %type of a function. Looking up at YO_TABLE declaration, you write
DECLARE
TYPE yo_table
IS
TABLE OF YO_TABLE;
Huh? table declaration is table of same variable you're declaring?
And this:
SELECT "D_ID"
INTO yo_table
FROM TABLE "(IREL_FN (X))";
You don't need quotes when casting table, and the x in IREL_FN (X) is a formal parameter, you need to replace it with the actual value what you need to pass
create or replace
PROCEDURE IRRELEVANT_SKATA (INSID IN NUMBER) AS ID T_ID_TABLE ;
BEGIN
DECLARE
YO_TABLE T_ID_TABLE;
BEGIN
select ID
into YO_TABLE
from table(IREL_FN(INSID));
EXCEPTION
WHEN NO_DATA_FOUND THEN dbms_output.put_line('NO DATA FOUND');
END;
END IRRELEVANT_TWEET;
<-----------------------------FUNCTION---------------------------------->
create or replace
FUNCTION IREL_FN ( D_ID IN NUMBER ) RETURN T_ID_TABLE AS
ID T_ID_TABLE;
BEGIN
BEGIN
SELECT CAST(
MULTISET(
SELECT "Id"
FROM "SOMETHINGCOPY"
WHERE "KATI" = (SELECT "EKEINO" FROM "AUTO" WHERE "Id"=D_ID)
INTO ID
FROM DUAL;
return ID;
EXCEPTION
WHEN NO_DATA_FOUND THEN dbms_output.put_line('null');
END;
END IREL_FN;
I hope I helped :)
I am answering to your question marked as duplicate (the problem with exact fetch).
I rewrote your code in the following way, hope it helps. I makes the Irel_fn to be a pipelined function, however you can still write Cast multiset if you like , however you need to use type constructor as well.
create table auto(id number)
this table is instead of your source "AUTO" (so I could compile it).
create or replace type t_id as object (id number);
/
Create or replace type t_id_table is table of t_id;
/
create or replace FUNCTION Irel_fn (x IN NUMBER) RETURN T_ID_TABLE PIPELINED
as
BEGIN
for rec in (select id from auto where id=x)
loop
Pipe row (t_id(rec.id));
end loop;
return;
end;
/
create or replace procedure Irrelevant_skata (insid in NUMBER) is
bob t_id_table;
BEGIN
select t_id(id) bulk collect into bob from table(irel_fn(insid));
END;

Using variables in PostgreSQL function

I get this error when I try to run a custom PostgreSQL function:
ERROR: query has no destination for result data
PostgreSQL functions are very new for me. I am working with Navicat for PostgreSQL 11.0.17.
I have a table named translations with three columns: id, english, français. Here is how I create my function in the Console window:
test=# CREATE FUNCTION add_translation(english varchar(160), français varchar(160))
RETURNS integer
AS $BODY$
DECLARE
translation_id integer;
BEGIN
INSERT INTO translations
("english", "français")
VALUES (english, français)
RETURNING id
AS translation_id;
RETURN translation_id;
END;
$BODY$
LANGUAGE plpgsql;
Query OK, 0 rows affected (0.02 sec)
When I call this from the Console window, I get a not-very-useful error message.
test=# add_translation('one', 'un');
ERROR: syntax error at or near "add_translation"
LINE 1: add_translation('one', 'un')
^
When I call it from the Design Function window, I get the error quoted at the top.
I specifically want to isolate translation_id, because in the final version of this function I want to insert the latest id from the translation table into a new record in a different table.
I have also tried with:
DECLARE
translation_id integer;
BEGIN
INSERT INTO translations
("english", "français")
VALUES (english, français);
SELECT LASTVAL() INTO translation_id;
RETURN translation_id;
END;
When I run this from the Design Function panel, it behaves correctly, but when I call it from the console I get the same error as before.
If you can recommend any good tutorials and examples for understanding how to use variables correctly in postgres functions, I would be most grateful.
From the console you need a select command
select add_translation('one', 'un');
or
select * from add_translation('one', 'un');
Your function can be plain SQL
create or replace function add_translation (
english varchar(160), français varchar(160)
) returns integer as $body$
insert into translations ("english", "français")
values (english, français)
returning id as translation_id;
$body$ language sql;
In plpgsql a setof some type must be "returned from" the query
create or replace function add_translation (
english varchar(160), français varchar(160)
) returns setof integer as $body$
begin
return query
insert into translations ("english", "français")
values (english, français)
returning id as translation_id;
end;
$body$ language plpgsql;
Or to return a single value do the insert inside a CTE
create or replace function add_translation (
english varchar(160), français varchar(160)
) returns integer as $body$
declare
translation_id integer;
begin
with i as (
insert into translations ("english", "français")
values (english, français)
returning id
)
select id into translation_id from i;
return translation_id;
end;
$body$ language plpgsql;

PostgreSQL: Call a Function More Than Once in FROM Clause

How can I call a function which returns records more than once in FROM clause? I understand that I have to specify a 'column definition list' when using a function that returns records. But how can I then use aliases for that function?
Example:
CREATE OR REPLACE FUNCTION foo(which_foo int) RETURNS SETOF RECORD AS
$BODY$BEGIN
IF which_foo=0 THEN
RETURN QUERY EXECUTE 'SELECT 1::int,2::int;';
ELSE
RETURN QUERY EXECUTE 'SELECT 1::int,2::int;';
END IF;
END$BODY$
LANGUAGE plpgsql;
SELECT * FROM foo(0) AS (a int, b int);;
SELECT * FROM foo(1) AS (c int, d int);
SELECT * FROM foo(0) AS (a int, b int), foo(1) AS (c int, d int);
The last select statement will fail with:
ERROR: table name "foo" specified more than once
I want to keep using the column definition list, because the function I want to use in the end has to be as generic as possible.
SELECT f0.*, f1.*
FROM
foo(0) AS f0 (a int, b int),
foo(1) AS f1 (c int, d int);
I understand that I have to specify a 'column definition list' when
using a function that returns records.
No, you do not. I wouldn't operate with anonymous records. Declare the return type, since you already know it:
CREATE OR REPLACE FUNCTION foo(which_foo int)
RETURNS TABLE (a int, b int) AS
$func$
BEGIN
IF which_foo = 0 THEN
RETURN QUERY SELECT 1,2;
ELSE
RETURN QUERY SELECT 1,2;
END IF;
END
$func$ LANGUAGE plpgsql;
And assuming you do not want to combine multiple calls into one row, you should use UNION ALL:
SELECT * FROM foo(0)
UNION ALL
SELECT * FROM foo(1);