ERROR: query has no destination for result data - sql

i have created a function in PostgreSQL to insert to the following
CREATE TABLE gtab83
(
orderid integer NOT NULL DEFAULT nextval('seq_gtab83_id'::regclass),
acid integer,
slno integer,
orderdte date
)
and created Function is
CREATE OR REPLACE FUNCTION funcInsert(iacid int,islno int,idate date) RETURNS int AS
$$
declare id_val int;
BEGIN
INSERT INTO GTAB83 (acid,slno,orderdte) VALUES (iacid,islno,idate) RETURNING orderid
into id_val;
return id_val;
END;
$$
LANGUAGE plpgsql;
when a execute the above function
select funcInsert(666,13,'2014-06-06'
getting this error
ERROR: query has no destination for result data
CONTEXT: PL/pgSQL function procgtab83(integer,integer,date) line 3 at SQL statement

create or replace function funcinsert(iacid int, islno int, idate date)
returns int as $$
declare id_val int;
begin
with i as (
insert into gtab83 (acid,slno,orderdte)
values (iacid,islno,idate)
returning orderid
)
select orderid into id_val
from i;
return id_val;
end;
$$ language plpgsql;
It can be much simpler as plain sql
create or replace function funcinsert(iacid int, islno int, idate date)
returns int as $$
insert into gtab83 (acid,slno,orderdte)
values (iacid,islno,idate)
returning orderid
;
$$ language sql;

This code is working:
postgres=# create table xx(a int);
CREATE TABLE
postgres=# create or replace function bu(int) returns int as
$$declare x int;
begin
insert into xx values($1) returning a into x;
return x;
end $$ language plpgsql;
CREATE FUNCTION
postgres=# select bu(10);
bu
────
10
(1 row)
And because it is same code as your, I expect, so you use some very old Postgres. I remember similar bug in pg, but it is more than five years fixed.

Related

Using a variable in GROUP BY clause

I want to use a single value variable defined in a stored procedure in a GROUP BY query as follows:
CREATE TABLE test_table
(
id uuid NOT NULL,
no int4 NOT NULL
);
CREATE TABLE bigger_table
(
id uuid NOT NULL,
no int4 NOT NULL,
count int4 NOT NULL,
time timestamp NOT NULL
);
CREATE OR REPLACE PROCEDURE test()
LANGUAGE plpgsql
AS
$$
DECLARE
v_now timestamp;
BEGIN
v_now = now();
INSERT INTO bigger_table (no, count, time)
SELECT no, COUNT(*), v_now FROM test_table
GROUP BY no;
END
$$;
Here, v_now is effectively a constant and I know it, but Postgres doesn't so it wants it be either included in GROUP BY clause or in an aggregation function. How can I convince it to use the variable here?
Have you tried to put an alias on v_now and use this alias on group by?
CREATE TABLE test_table
(
id uuid NOT NULL,
no int4 NOT NULL
);
CREATE OR REPLACE PROCEDURE test()
LANGUAGE plpgsql
AS
$$
DECLARE
v_now timestamp;
BEGIN
v_now = now();
SELECT no, COUNT(*), now() v_now FROM test_table
GROUP BY no, v_now;
END
$$;
Yech. People love constraint. But...
You cannot INSERT INTO bigger_table (no, count, time) because You already defined id uuid NOT NULL !
CREATE OR REPLACE PROCEDURE test()
LANGUAGE plpgsql
AS
$$
DECLARE
v_now timestamp;
BEGIN
v_now := now();
INSERT INTO bigger_table (id,no, count, time)
SELECT gen_random_uuid(),
no,
COUNT(*) over(partition by no ),
v_now FROM test_table;
END
$$;
Don't use timestamp: https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_timestamp_.28without_time_zone.29
now() return timestamp with time zone !
select pg_typeof(now()); return timestamp with time zone

How to return multiple inserted rows from a Stored function with insert select statement?

Sample Problem with queries Link
Not able to get any inserted row in the RETURNING statement with INSERT and SELECT command even after adding RETURN NEXT; RETURN ;
SCHEMA FOR USER TABLE
create table "user" (name text not null, updated_time TIMESTAMP NOT
NULL DEFAULT CURRENT_TIMESTAMP );
function which needs to be updated to return inserted rows
CREATE OR REPLACE FUNCTION testFn()
RETURNS table (name character varying , updated_time timestamp without time zone ) AS $$ DECLARE BEGIN
insert into "user" (name , updated_time)
select 'alex',now()
union
select 'alex2',now()
returning name, updated_time;
END;
$$ LANGUAGE plpgsql;
This function only inserts into DB but doesnt return the inserted rows with updated time on calling the function
it return no output on
select * from testFn()
Make it a language sql function:
CREATE OR REPLACE FUNCTION testFn()
RETURNS table (name character varying , updated_time timestamp without time zone )
AS
$$
insert into "user" (name , updated_time)
values
('alex', now()),
('alex2', now())
returning "user".name, "user".updated_time;
$$
LANGUAGE sql;
With a language plpgsql you would need a return query, rather then just putting the insert into it.
CREATE OR REPLACE FUNCTION testFn()
RETURNS table (name character varying , updated_time timestamp without time zone )
AS
$$
begin
return query
insert into "user" (name , updated_time)
values
('alex', now()),
('alex2', now())
returning "user".name, "user".updated_time;
end;
$$
LANGUAGE plpgsql;
To run the function use:
select *
from testfn();
Online example
It is much simpler to do with a language sql function. Try this (based on the previous version of your function):
CREATE OR REPLACE FUNCTION sp_post_items(i_data json)
RETURNS table (fulfiller_id text,item_id text, order_id text, status_id integer, item_updated_time timestamp)
AS $function$
insert into vw_item_status_detail
(fulfiller_id ,item_id ,order_id , status_id, sku_code, decoration_technology, quantity, item_updated_time)
select
i_data->>'fulfillerId',
t->>'itemId',
i_data->>'orderId',
1000,
t->>'skuCode',
t->>'decorationTechnology',
10,
now()
from json_array_elements(i_data -> 'items') t
returning fulfiller_id, item_id, order_id, status_id, item_updated_time;
$function$
LANGUAGE sql;
or for the updated function:
CREATE OR REPLACE FUNCTION testFn()
RETURNS table (name text, updated_time timestamp without time zone ) AS
$$
insert into "user" (name , updated_time)
select 'alex',now()
union
select 'alex2',now()
returning name, updated_time;
$$ LANGUAGE sql;

Execute INSERT INTO in PLPGSQL using variables as values

I'm trying to create function, which adds a record with given variables as values. My code:
CREATE OR REPLACE FUNCTION ADD_FILM(id INTEGER, t VARCHAR, y INTEGER, p REAL) RETURNS VARCHAR AS $$
DECLARE
query VARCHAR;
BEGIN
query = 'insert into films (id_film, title, year_production, price) values ('||id||','||t||','||y||','||p||')';
EXECUTE query;
RETURN 'OK';
EXCEPTION
WHEN UNIQUE_VIOLATION THEN
RAISE NOTICE 'Incorrect ID, next available ID set';
RETURN 0;
END;
$$ LANGUAGE PLPGSQL;
SELECT ADD_FILM(1,'aaa','2020','10');
Following function execution ends with error. What's wrong with syntax?
ERROR: column "aaa" does not exist
I'd rather do like this:
CREATE OR REPLACE FUNCTION ADD_FILM(id INTEGER, t VARCHAR, y INTEGER, p REAL) RETURNS
VARCHAR AS $$
BEGIN
insert into films (id_film, title, year_production, price) values (id,t,y,p);
RETURN 'OK';
....
....
See this link: https://www.postgresqltutorial.com/postgresql-create-procedure/
And call it:
CALL ADD_FILM(1,'aaa','2020','10');
Another possible solution with EXECUTE:
create table films
(
id_film int,
title varchar,
year_production int,
price real
);
CREATE TABLE
CREATE OR REPLACE FUNCTION ADD_FILM(id INTEGER, t VARCHAR, y INTEGER, p REAL) RETURNS VARCHAR AS $$
DECLARE
query VARCHAR;
BEGIN
query = 'insert into films (id_film, title, year_production, price) values ($1,$2,$3,$4)';
EXECUTE query USING id, t, y, p;
RETURN 'OK';
EXCEPTION
WHEN UNIQUE_VIOLATION THEN
RAISE NOTICE 'Incorrect ID, next available ID set';
RETURN 0;
END;
$$ LANGUAGE PLPGSQL;
CREATE FUNCTION
SELECT ADD_FILM(1,'aaa','2020','10');
add_film
----------
OK
(1 row)
select * from films;
id_film | title | year_production | price
---------+-------+-----------------+-------
1 | aaa | 2020 | 10
(1 row)

How correctly create multiple entries by arrays in PostgreSQL?

In PostgreSQL database I have table which looks like this:
| question_id | question_text | widget | required | position |
|-------------|---------------|--------|----------|----------|
| int | text | int | boolean | int |
Second table which called factors_questions_relationship looks like this:
| factor_id | question_id |
|-------------|---------------|
| int | text |
I am trying to create function which would create multiple rows and return array of ids of new created entries. How correctly to make such function?
CREATE OR REPLACE FUNCTION factorio(
FACTOR_IDENTIFIER INT,
TEXT_ARR VARCHAR[],
WIDGET_ARR INT[],
REQUIRED_ARR BOOLEAN[],
POSITION_ARR INT[]
) RETURNS SETOF INT AS $$
BEGIN
RETURN QUERY
WITH RESULT_SET AS (
INSERT INTO QUESTIONS (TEXT, WIDGET, REQUIRED, POSITION)
SELECT
UNNEST(ARRAY[TEXT_ARR]) AS TEXT,
UNNEST(ARRAY[WIDGET_ARR]) AS WIDGET,
UNNEST(ARRAY[REQUIRED_ARR]) AS REQUIRED,
UNNEST(ARRAY[POSITION_ARR]) AS POSITION
RETURNING ID
)
--
INSERT INTO factors_questions_relationship (FACTOR_ID, QUESTION_ID)
SELECT FACTOR_IDENTIFIER FACTOR_ID, QUESTION_ID FROM UNNEST(ARRAY[array_agg(SELECT ID FROM RESULT_SET)]) QUESTION_ID
--
SELECT ID FROM RESULT_SET;
END;
$$ LANGUAGE plpgsql;
You can simply unnest them in columns
select
unnest(array['quick','brown','fox']) as question_text,
unnest(array[1,2,3]) as widget_id
Whereas putting them in FROM clause, would result to cartesian product:
select question_text, widget_id
from
unnest(array['quick','brown','fox']) as question_text,
unnest(array[1,2,3]) as widget_id
Output:
To obtain the Ids generated from newly-inserted records, use return query + returning id combo. Sample test:
create table z
(
id int generated by default as identity primary key,
question_text text
);
create or replace function insert_multiple_test()
returns table (someid int) as
$$
begin
return query
with resulting_rows as
(
insert into z(question_text) values
('hello'),
('你好'),
('hola')
returning id
)
select id from resulting_rows;
end;
$$ language 'plpgsql';
select * from insert_multiple_test();
Output:
Here's for SETOF:
create table z(id int generated by default as identity primary key, question_text text);
create or replace function insert_multiple_test()
returns setof int
as
$$
begin
return query
with resulting_rows as
(
insert into z(question_text) values
('hello'),
('你好'),
('hola')
returning id
)
select id from resulting_rows;
end;
$$ language 'plpgsql';
select x.the_id from insert_multiple_test() as x(the_id);
Output:
If you don't need to run multiple queries, you can just use LANGUAGE 'sql', it's simpler:
create table z
(
id int generated by default as identity primary key,
question_text text
);
create or replace function insert_multiple_test()
returns setof int as
$$
insert into z(question_text) values
('hello'),
('你好'),
('hola')
returning id;
$$ language 'sql';
select x.id_here from insert_multiple_test() as x(id_here);
Output:

How to return PK from insert query?

I have a postgresql table with sequence:
CREATE TABLE A (
id integer NOT NULL DEFAULT nextval('a_seq'::regclass),
X integer,
Y integer,
Z boolean default false,
CONSTRAINT A_pkey PRIMARY KEY (id)
)
I have an insert statment in function as follows:
insert into A(x,y) select $1,getdig();
i want this insert to return the id the row was given to a function varabile called A_id
It should be something like:
CREATE OR REPLACE FUNCTION bbb(m integer)
RETURNS integer AS
$BODY$
declare
A_id int;
begin
insert into A(x,y) select $1,getdig() RETURNING id into A_id;
actions using A_id like:
update A set z=True where id=A_id;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
How do I do that?
There is no need for the select:
CREATE OR REPLACE FUNCTION bbb(m integer)
RETURNS integer AS
$BODY$
declare
A_id int;
begin
insert into A(x,y)
values ($1,getdig())
RETURNING id into A_id;
-- actions using A_id like:
update A set z=True where id=A_id;
return a_id; -- don't forget to return something!
end;
$BODY$
LANGUAGE plpgsql VOLATILE
You use the returning clause:
with i as (
insert into A(x,y)
select $1, getdig()
returning id
)
select *
from i;
Technically, the CTE is not necessary. But I prefer that queries that return values start with SELECT.