I'm new at postgresql and i'm trying to make a function that will return the trimmed mean about all table data. When i try to run this query i get the error message:
ERROR: query has no destination for result data
This is the function:
CREATE OR REPLACE FUNCTION media_truncada(
coluna TEXT,
percentualTruncado NUMERIC)
RETURNS REAL AS $$
BEGIN
IF coluna = 'tempo_ciclo' THEN
WITH limites AS
(SELECT
(AVG(evento_tempo_ciclo.tempo_ciclo) - STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo) * percentualTruncado) as limite_inferior,
(AVG(evento_tempo_ciclo.tempo_ciclo) + STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo) * percentualTruncado) as limite_superior
FROM evento_tempo_ciclo)
SELECT
AVG(evento_tempo_ciclo.tempo_ciclo) as media
FROM evento_tempo_ciclo
WHERE tempo_ciclo BETWEEN (SELECT limite_inferior FROM limites) AND (SELECT limite_superior FROM limites);
ELSE
WITH limites AS
(SELECT
(AVG(evento_tempo_ciclo.tempo_ciclo_liquido) - STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo_liquido) * percentualTruncado) as limite_inferior,
(AVG(evento_tempo_ciclo.tempo_ciclo_liquido) + STDDEV_SAMP(evento_tempo_ciclo.tempo_ciclo_liquido) * percentualTruncado) as limite_superior
FROM evento_tempo_ciclo)
SELECT
AVG(evento_tempo_ciclo.tempo_ciclo_liquido) as media
FROM evento_tempo_ciclo
WHERE tempo_ciclo BETWEEN (SELECT limite_inferior FROM limites) AND (SELECT limite_superior FROM limites);
END IF;
RETURN media;
END;
$$ LANGUAGE plpgsql;
You are getting this error message because you execute a query in your function, but nothing happens with the output. RETURN media doesn't actually return anything because media isn't defined, it's only the alias of the column in your query, which is unknown after the query ends.
You will either need to:
Assign the result to a variable:
DECLARE media REAL;
BEGIN
WITH (...) SELECT AVG(evento_tempo_ciclo.tempo_ciclo_liquido) INTO media ...
RETURN media;
END ...
Or return the query as the result:
RETURN QUERY AS WITH (...) SELECT ...
Or just use an SQL function rather than plpgsql:
CREATE OR REPLACE FUNCTION media_truncada(
coluna TEXT,
percentualTruncado NUMERIC)
RETURNS REAL AS $$
...
$$ LANGUAGE sql;
If you aren't 100% certain that your query will never return more than 1 result, you will need to add a LIMIT 1 to your query.
Related
I am trying to fetch data from remote db by using dblink through function but getting an error "query has no destination for result data". I am using plpgsql language to do the same.
Function:
CREATE OR REPLACE FUNCTION fun()
RETURNS text AS
$$
begin
select dblink_connect(
'port=5432 dbname=test user=postgres password=****');
WITH a AS (
SELECT *
FROM dblink(
'SELECT slno,fname,mname,lname
FROM remote_tbl'
) AS t (slno int, fname text, mname text, lname text)
)
, b AS (
INSERT INTO temptab1
SELECT slno, name
FROM a
)
, c AS (
INSERT INTO temptab2
SELECT slno, name
FROM a
)
INSERT INTO temptab3
SELECT slno, name
FROM a;
select dblink_disconnect();
end;
$$
LANGUAGE plpgsql;
Calling Function:
select fun();
Error: query has no destination for result data
The stored procedure won't just return the result of the last SELECT. You need to actually return the value:
CREATE OR REPLACE FUNCTION fun() RETURNS text AS $$
BEGIN
--- ....
RETURN(SELECT dblink_disconnect());
END
$$ LANGUAGE plpgsql;
You're getting the error because Postgres expects the function to return something of type text, but your function doesn't return anything.
Use a plain SQL function instead of PL/PgSQL, or use SELECT INTO and ordinary RETURN.
Reason for the error you're getting is because there is no return in between your BEGIN and END for example:
BEGIN
update mytable set lastcodeused = to_char(cast(lastcodeused as INTEGER)+1, 'FM999999999999999999') where
classid = classIdVar and appid= appIdInt
RETURNING concat(pageUniqueCode,lastcodeused) as pageUniqueCode
into taskcode;
return taskcode;
END;
If you have this error using a pgplsql procedure or function, and you are sure that the return is defined correctly, there exists a different non-intuitive cause. I needed some time to realize this so I think it is worth sharing. I had a function like this:
CREATE OR REPLACE FUNCTION "db".fn_x(
id integer)
RETURNS TABLE(b_val varchar(100), c_val varchar(100))
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
var_b_val varchar(100);
var_c_val varchar(100);
BEGIN
select var_b, var_c
-- Missing INTO clause was the cause of the error.
var_b_val, var_c_val
from "db".table_y where y_id = id;
return query(select var_b_val, var_c_val);
END;
$BODY$;
Just adding that missing INTO clause made the function work correctly.
In conclusion, this error can also trigger on silent syntax errors.
I am trying to fetch data from remote db by using dblink through function but getting an error "query has no destination for result data". I am using plpgsql language to do the same.
Function:
CREATE OR REPLACE FUNCTION fun()
RETURNS text AS
$$
begin
select dblink_connect(
'port=5432 dbname=test user=postgres password=****');
WITH a AS (
SELECT *
FROM dblink(
'SELECT slno,fname,mname,lname
FROM remote_tbl'
) AS t (slno int, fname text, mname text, lname text)
)
, b AS (
INSERT INTO temptab1
SELECT slno, name
FROM a
)
, c AS (
INSERT INTO temptab2
SELECT slno, name
FROM a
)
INSERT INTO temptab3
SELECT slno, name
FROM a;
select dblink_disconnect();
end;
$$
LANGUAGE plpgsql;
Calling Function:
select fun();
Error: query has no destination for result data
The stored procedure won't just return the result of the last SELECT. You need to actually return the value:
CREATE OR REPLACE FUNCTION fun() RETURNS text AS $$
BEGIN
--- ....
RETURN(SELECT dblink_disconnect());
END
$$ LANGUAGE plpgsql;
You're getting the error because Postgres expects the function to return something of type text, but your function doesn't return anything.
Use a plain SQL function instead of PL/PgSQL, or use SELECT INTO and ordinary RETURN.
Reason for the error you're getting is because there is no return in between your BEGIN and END for example:
BEGIN
update mytable set lastcodeused = to_char(cast(lastcodeused as INTEGER)+1, 'FM999999999999999999') where
classid = classIdVar and appid= appIdInt
RETURNING concat(pageUniqueCode,lastcodeused) as pageUniqueCode
into taskcode;
return taskcode;
END;
If you have this error using a pgplsql procedure or function, and you are sure that the return is defined correctly, there exists a different non-intuitive cause. I needed some time to realize this so I think it is worth sharing. I had a function like this:
CREATE OR REPLACE FUNCTION "db".fn_x(
id integer)
RETURNS TABLE(b_val varchar(100), c_val varchar(100))
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
var_b_val varchar(100);
var_c_val varchar(100);
BEGIN
select var_b, var_c
-- Missing INTO clause was the cause of the error.
var_b_val, var_c_val
from "db".table_y where y_id = id;
return query(select var_b_val, var_c_val);
END;
$BODY$;
Just adding that missing INTO clause made the function work correctly.
In conclusion, this error can also trigger on silent syntax errors.
I have spent good amount of time trying to figure it out and I haven't been able to resolve it. So, I need your help please.
I am trying to write a PL/pgSQL function that returns multiple rows. The function I wrote is shown below. But it is not working.
CREATE OR REPLACE FUNCTION get_object_fields()
RETURNS SETOF RECORD
AS
$$
DECLARE result_record keyMetrics;
BEGIN
return QUERY SELECT department_id into result_record.visits
from fact_department_daily
where report_date='2013-06-07';
--return result_record;
END
$$ LANGUAGE plpgsql;
SELECT * FROM get_object_fields;
It is returning this error:
ERROR: RETURN cannot have a parameter in function returning set;
use RETURN NEXT at or near "QUERY"
After fixing the bugs #Pavel pointed out, also define your return type properly, or you have to provide a column definition list with every call.
This call:
SELECT * FROM get_object_fields()
... assumes that Postgres knows how to expand *. Since you are returning anonymous records, you get an exception:
ERROR: a column definition list is required for functions returning "record"
One way (of several) to fix this is with RETURNS TABLE (Postgres 8.4+):
CREATE OR REPLACE FUNCTION get_object_fields()
RETURNS TABLE (department_id int) AS
$func$
BEGIN
RETURN QUERY
SELECT department_id
FROM fact_department_daily
WHERE report_date = '2013-06-07';
END
$func$ LANGUAGE plpgsql;
Works for SQL functions just the same.
Related:
PostgreSQL: ERROR: 42601: a column definition list is required for functions returning "record"
I see more bugs:
first, a SET RETURNING FUNCTIONS call has following syntax
SELECT * FROM get_object_fields()
second - RETURN QUERY forwards query result to output directly. You cannot store this result to variable - it is not possible ever in PostgreSQL now.
BEGIN
RETURN QUERY SELECT ....; -- result is forwarded to output directly
RETURN; -- there will not be any next result, finish execution
END;
third - these simple functions is better to implement in SQL languages
CREATE OR REPLACE FUNCTION get_object_fields()
RETURNS SETOF RECORD AS $$
SELECT department_id WHERE ...
$$ LANGUAGE sql STABLE;
Here's one way
drop function if exists get_test_type();
drop type if exists test_comp;
drop type if exists test_type;
drop type if exists test_person;
create type test_type as (
foo int,
bar int
);
create type test_person as (
first_name text,
last_name text
);
create type test_comp as
(
prop_a test_type[],
prop_b test_person[]
);
create or replace function get_test_type()
returns test_comp
as $$
declare
a test_type[];
b test_person[];
x test_comp;
begin
a := array(
select row (m.message_id, m.message_id)
from message m
);
-- alternative 'strongly typed'
b := array[
row('Bob', 'Jones')::test_person,
row('Mike', 'Reid')::test_person
]::test_person[];
-- alternative 'loosely typed'
b := array[
row('Bob', 'Jones'),
row('Mike', 'Reid')
];
-- using a select
b := array (
select row ('Jake', 'Scott')
union all
select row ('Suraksha', 'Setty')
);
x := row(a, b);
return x;
end;
$$
language 'plpgsql' stable;
select * from get_test_type();
CREATE OR REPLACE FUNCTION get_object_fields()
RETURNS table (department_id integer)
AS
$$
DECLARE result_record keyMetrics;
BEGIN
return QUERY
SELECT department_id
from fact_department_daily
where report_date='2013-06-07';
--return result_record;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM get_object_fields()
i try a query that runs on mssql however does not run postgreSQL...
SQL Query is..
IF EXISTS (SELECT * FROM Kategoriler WHERE KategoriId = 119)
BEGIN
SELECT * FROM Kategoriler
END
ELSE
SELECT * FROM Adminler
i searched it and i found in stackoverflow
DO
$BODY$
BEGIN
IF EXISTS (SELECT 1 FROM orders) THEN
DELETE from orders;
ELSE
INSERT INTO orders VALUES (1,2,3);
END IF;
END;
$BODY$
but i do not want to use DO or, $body etc... I do not want to write any function or other etc...
i want to write only if else statement in postgreSQL... Please help me...
T-SQL supports some procedural statement like IF. PostgreSQL doesn't support it, so you cannot rewrite your query to postgres simply. Sometime you can use Igor's solution, sometime you can use plpgsql (functions) and sometime you have to modify your application and move procedural code from server to client.
Try something like
SELECT *
FROM Kategoriler
UNION ALL
SELECT *
FROM Adminler
WHERE NOT EXIST (SELECT * FROM Kategoriler WHERE KategoriId = 119)
Will only work if Kategoriler and Adminler have same structure. Otherwise you need to specify list of fields instead of *
In my case I needed to know if a record existed.
I had to write a function
CREATE OR REPLACE FUNCTION public.pro_device_exists(vdn character varying)
RETURNS boolean
LANGUAGE plpgsql
AS $function$
BEGIN
IF EXISTS (SELECT 1 FROM tags WHERE device_name = upper(vdn)) THEN
return true;
ELSE
return false;
END IF;
END; $function$
Then I was able to call this function in my code ... just a portion of my code
if pro_device_exists(vdn) then
update tags
set device_id = 11 where device_id = pro_device_id(vdn) and tag_type=10;
update tags
set device_id = pro_device_id(vdn) where tag_id = vtag_id;
vmsg = (select 'Device Now set to ' || first_name || ' ' || last_name from tags where tag_id=vtag_id);
vaction = 'Refresh Device Data';
else
vmsg = 'Device is not registered on this system';
vaction = 'No Nothing';
end if;
I'm trying to create a PL/pgSQL function, which should populate a temporary table and then return all rows from it (it will be a join later), but I don't know which return type to specify for it:
create or replace function pref_daily_misere() returns void as $BODY$
begin
create temporary table temp_best (id varchar not null) on commit drop;
insert into temp_best (id) select id from pref_money where
yw = to_char(current_timestamp - interval '1 week', 'IYYY-IW')
order by money desc limit 10;
select id from temp_best;
end;
$BODY$ language plpgsql;
The statements above work on their own, but give me the error
# select pref_daily_misere();
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function "pref_daily_misere" line 7 at SQL statement
when I try to call it in my PostgreSQL 8.4.11 database.
This is probably because I have wrongly specified the returns void above, but I don't know which return type to use instead and omitting the return type is a compile error.
You want to use a setof varchar return type and then return query ... inside the function. From the fine manual:
39.6.1.2. RETURN NEXT and RETURN QUERY
RETURN NEXT expression;
RETURN QUERY query;
RETURN QUERY EXECUTE command-string [ USING expression [, ... ] ];
When a PL/pgSQL function is declared to return SETOF sometype, the procedure to follow is slightly different. In that case, the individual items to return are specified by a sequence of RETURN NEXT or RETURN QUERY commands, and then a final RETURN command with no argument is used to indicate that the function has finished executing.
I think you want something more like this:
create or replace function pref_daily_misere() returns setof varchar as $BODY$
begin
create temporary table temp_best (id varchar not null) on commit drop;
insert into temp_best (id)
select id
from pref_money
where yw = to_char(current_timestamp - interval '1 week', 'IYYY-IW')
order by money
desc limit 10;
return query select id from temp_best;
return;
end;
$BODY$ language plpgsql;
However, the temp table is pointless here:
Note: The current implementation of RETURN NEXT and RETURN QUERY stores the entire result set before returning from the function, as discussed above.
So PostgreSQL is computing the entire result set and caching it by itself. You could do this:
create or replace function pref_daily_misere() returns setof varchar as $BODY$
begin
return query
select id
from pref_money
where yw = to_char(current_timestamp - interval '1 week', 'IYYY-IW')
order by money
desc limit 10;
return;
end;
$BODY$ language plpgsql;
I'm pretty sure the temp table is going to be dropped at the end of your function anyway so you should get rid of it.