issue with create function in PostgreSQL - postgresql

I am trying to get year from orderdate function
type
orderdate date
create or replace function getyearfromdate(year date)returns
table
as
$$
begin
return QUERY execute (
'select extract (year from orderdate) FROM public.orderalbum'
);
end;
$$
language plpgsql;
I write a logic but not able to create a function
I want to return year from the orderdate.
I want to pass a orderdate and return year from the function
I am facing below error
ERROR: syntax error at or near "as"
LINE 3: as
^
SQL state: 42601
Character: 70

Based on your comments, it seems you only want a wrapper around the extract() function. In that case you do not want a set returning function. And you don't need PL/pgSQL or even dynamic SQL for this:
create or replace function getyearfromdate(p_date_value date)
returns int --<< make this a scalar function!
as
$$
select extract(year from p_date_value)::int;
$$
language sql;
Note that I renamed your parameter as I find a parameter named year for a date value highly confusing.
That function can then be used as part of a SELECT list:
SELECT ..., getyearfromdate(orderdate)
FROM public.orderalbum
GROUP BY ...
Original answer based on the question before comments clarified it.
As documented in the manual returns table requires a table definition.
Your use of dynamic SQL is also useless.
create or replace function getyearfromdate(year date)
returns table (year_of_month int)
as
$$
begin
return QUERY
select extract(year from orderdate)::int
FROM public.orderalbum;
end;
$$
language plpgsql;
I am not sure why you are passing a parameter to the function that you never use.

Related

PostgreSQL INSERT INTO - ON CONFLICT column name is ambiguous [duplicate]

I've created a function like this.
create or replace function pesquisar_imoveis_residenciais_venda()
returns table(preco decimal)
as $$
begin
select preco from casa_venda;
end; $$
language 'plpgsql';
When I call it
select pesquisar_imoveis_residenciais_venda()
I get the column reference preco is ambiguous.
I've visited some related question. But they are too difficult to follow, very complex functions.
The columns defined in the RETURNS QUERY clause are variables in the PL/pgSQL function body, so the ambiguity is between the variable preco and the table column of the same name. You need to qualify the reference with either the table name or the function name to disambiguate that.
But your function definition has other issues. I think you want:
create or replace function pesquisar_imoveis_residenciais_venda()
returns table(preco decimal)
as $$
begin
return query select cv.preco from casa_venda cv;
end; $$
language 'plpgsql';
select *
from pesquisar_imoveis_residenciais_venda();
Here is a db<>fiddle.
You can override the plpgsql.variable_conflict configuration parameter:
create or replace function pesquisar_imoveis_residenciais_venda()
returns table(preco decimal)
as $$
#variable_conflict use_column
begin
select preco from casa_venda;
end; $$
language 'plpgsql';
This assumes you want to use the column value and not the variable value. If that's not the case then specify #variable_conflict use_variable instead.
See the docs for further details.
it means column name Preco in table casa_venda is not exist or exist more than 1 time.

Difficulties using Postgresql's EXTRACT tool via function call

I'm trying to figure out how to use the Postgresql EXTRACT function to convert a given date_variable into its equivalent day of the week. I understand that it will convert the date_variable into a numbering from 0 - 6 (0 is Sunday, 6 is Saturday etc)
I've created a simple table to test my queries. Here I will attempt to convert the start_date into its DOW equivalent.
DROP TABLE IF EXISTS test;
CREATE TABLE test(
start_date date PRIMARY KEY,
end_date date
);
INSERT INTO test (start_date, end_date) VALUES ('2021-03-31', '2021-03-31'); -- Today (wed), hence 3
INSERT INTO test (start_date, end_date) VALUES ('2021-03-30', '2021-03-30'); -- Yesterday (tues), hence 2
INSERT INTO test (start_date, end_date) VALUES ('2021-03-29', '2021-03-29'); -- Day before (mon), hence 1
If I were to run the query below
SELECT (EXTRACT(DOW FROM t.start_date)) AS day FROM test t;
It works fine, and returns the result as intended (returns a single column table with values (3, 2, 1) respectively.)
However, when I attempt to write a function to return the exact same query
CREATE OR REPLACE FUNCTION get_day()
RETURNS TABLE (day integer) AS $$
BEGIN
RETURN QUERY
SELECT (EXTRACT(DOW FROM t.start_date)) as day
FROM test t;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM get_day(); -- throws error "structure of query does not match function result type"
I get an error instead. I cant seem to find the issue and don't know what is causing it.
extract() returns a double precision value, but your function is declared to return an integer. You need to cast the value:
CREATE OR REPLACE FUNCTION get_day()
RETURNS TABLE (day integer) AS $$
BEGIN
RETURN QUERY
SELECT EXTRACT(DOW FROM t.start_date)::int as day
FROM test t;
END;
$$ LANGUAGE plpgsql;
But you don't really need PL/pgSQL for this, a language SQL function would also work.
CREATE OR REPLACE FUNCTION get_day()
RETURNS TABLE (day integer) AS $$
SELECT EXTRACT(DOW FROM t.start_date)::int as day
FROM test t;
$$
LANGUAGE sql
stable;
As you are not passing any parameters, I would actually use a view for this:
create or replace view day_view
AS
SELECT EXTRACT(DOW FROM t.start_date)::int as day
FROM test t;
The extract function returns values of type double precision.
You declare result to be integer.
You should cast the result of EXTRACT to integer:
CREATE OR REPLACE FUNCTION get_day()
RETURNS TABLE (day integer) AS $$
BEGIN
RETURN QUERY
SELECT EXTRACT(DOW FROM t.start_date)::integer as day
FROM test t;
END;
$$ LANGUAGE plpgsql;

Postgresql Common Expression Table (CTE) in Function

I'm trying to use CTE in PostgreSQL function and returning the CTE as table. But I couldn't manage to compile the function as it says ERROR: syntax error at end of input in the select query. Could someone point me what I'm missing here.
CREATE OR REPLACE FUNCTION my_func(name varchar) RETURNS TABLE (hours integer) AS $$
BEGIN
WITH a AS (
SELECT hours FROM name_table tbl where tbl.name= name; <- giving error here
)
RETURN QUERY SELECT hours FROM a;
END;
$$ LANGUAGE plpgsql;
PS: I'm on PostgreSQL 9.6 if that helps.
The CTE expression is part of the query, so it needs to come immediately after the return query clause, not before it. Additionally, to avoid syntax errors later on, you should select a parameter name that ins't ambiguous with the names of the columns, and fully qualify the columns you're querying:
CREATE OR REPLACE FUNCTION my_func(v_name varchar)
RETURNS TABLE (hours integer) AS $$
BEGIN
RETURN QUERY WITH a AS (
SELECT tbl.hours
FROM name_table tbl
WHERE name = v_name
)
SELECT a.hours FROM a;
END;
$$ LANGUAGE plpgsql;

Postgres: Function check duplicates in table

I have table with multiple duplicates and I want to make from these a function. Could you please help me to make a function from this code? thanks.
SELECT id_member,id_service,amount,date, count(*) as number_of_duplicates
from evidence
GROUP BY id_member,id_service,amount,date
HAVING COUNT(*) > 1;
CREATE OR REPLACE FUNCTION check_for_duplicates()
RETURNS VOID AS
$BODY$
BEGIN
SELECT id_member,id_service,amount,date, count(*) as number_of_duplicates
from evidence
GROUP BY id_member,id_service,amount,date
HAVING COUNT(*) > 1;
END;
$BODY$
LANGUAGE ‘plpgsql‘;
If a function should return a result set it needs to be declared as returns table () or returns setof
You also don't need a PL/pgSQL function for that, a simple SQL function will do and is more efficient:
CREATE OR REPLACE FUNCTION check_for_duplicates()
RETURNS table (id_member integer, id_service integer, amount numeric, date date, number_of_duplicates bigint)
$BODY$
SELECT id_member,id_service,amount,date, count(*) as number_of_duplicates
from evidence
GROUP BY id_member,id_service,amount,date
HAVING COUNT(*) > 1;
$BODY$
LANGUAGE sql;
You didn't show us the definition of the table evidence so I had to guess the data type of the columns. You will need to adjust the types in the returns table (...) part to match the types from the table.
Having said that: I would create a view for things like that, not a function.
Unrelated, but: date is a horrible name for a column. For one because it's also a keyword but more importantly it doesn't document what the column contains: a release date? An expiration date? A due date?

Run text as a query

I have a table with 2 columns . The first a serial and the 2nd is a query that stored as a text.
To more simple the question , at the end: I wish to create a function which I will enter the number of the serial as a parameter and the function will return me the result of the query which is found in the 2nd column.
I know I have to use the command 'execute' from other questions I saw here on stack.
Even before the end result, I made this simple function:
CREATE OR REPLACE FUNCTION public.try1()
RETURNS TABLE(datery timestamp without time zone)
LANGUAGE plpgsql
AS $function$
declare
stmt text;
BEGIN
stmt :='SELECT b FROM chks where a=4';
RETURN QUERY
execute stmt ;
END
$function$
The result of this query select b form chks where a=4 is:
'select now()::timestamp without time zone'
When I am running the function I get cast error which tells me the reutrn of th fuction is varchar and not timestamp and if I change the return type to varchar I get as a result the query itself and not the result of the query.
What am I missing here?
In any case, is there a more simple way to do this?
I am asking this both for my simple function and for the function with the parameter I have mentioned before.
Try something like this:
CREATE OR REPLACE FUNCTION public.try1(query_number numeric)
RETURNS TABLE(datery timestamp without time zone)
AS $function$
DECLARE
stmt text;
BEGIN
SELECT b INTO stmt
FROM chks
WHERE a=query_number;
RETURN QUERY EXECUTE stmt;
END
$function$
LANGUAGE plpgsql STRICT;