I found this article:
http://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions
and I'm trying to use it as an example for my function. I am selecting different columns from different tables, and trying to return a set of records.
Here's my code:
CREATE OR REPLACE FUNCTION get_details_for_widget(widgetid integer)
RETURNS SETOF widgetdetails AS
$BODY$
DECLARE
rec widgetdetails %rowtype;
BEGIN
FOR rec IN (
SELECT widget_details.id, widget_details.contact_id, widget_details.priority, widget_owner.contact
FROM widget_details, widget_owner
WHERE widget_details.rid=widgetid
AND widget_details.active_yn = 't'
AND widget_owner.id=widget_details.contact_id
Order by widget_details.priority ASC)
LOOP
RETURN NEXT rec;
END LOOP;
END;
$BODY$
LANGUAGE plpgsql;
When I try to compile this code, I get the error the the type "widgetdetails" does not exist. In line with the example in the wiki, I changed my logic to look like this:
CREATE OR REPLACE FUNCTION get_details_for_widget(widgetid integer)
RETURNS SETOF widgetdetails AS
'SELECT widget_details.id, widget_details.contact_id,
widget_details.priority, widget_owner.contact
FROM widget_details, widget_owner
WHERE widget_details.rid=widgetid
AND widget_details.active_yn = "t"
AND widget_owner.id=widget_details.contact_id
Order by widget_details.priority ASC'
$BODY$
DECLARE
rec widgetdetails %rowtype;
BEGIN
FOR rec IN (
SELECT widget_details.id, widget_details.contact_id, widget_details.priority, widget_owner.contact
FROM widget_details, widget_owner
WHERE widget_details.rid=widgetid
AND widget_details.active_yn = 't'
AND widget_owner.id=widget_details.contact_id
Order by widget_details.priority ASC)
LOOP
RETURN NEXT rec;
END LOOP;
END;
$BODY$
LANGUAGE plpgsql;
It gives me an error that says:
ERROR: syntax error at or near "$BODY$
But I can't seem to see / find the problem.
The syntax you tried for the RETURNS
clause is foreign to Postgres.
Your code is much more complicated than it needs to be. You don't need PL/pgSQL for such a simple function. Use a plain SQL function instead:
CREATE OR REPLACE FUNCTION get_details_for_widget(widgetid integer)
RETURNS TABLE (id int, contact_id int, priority int, contact text)
LANGUAGE sql AS
$func$
SELECT d.id, d.contact_id, d.priority, o.contact
FROM widget_details d
JOIN widget_owner o ON o.id = d.contact_id
WHERE d.rid = widgetid -- where does widgetid come from?
AND d.active_yn = 't'
ORDER BY d.priority;
$func$
RETURNS TABLE
defines an ad-hoc row type. Adapt column types to your actual (undisclosed) table definitions. (This part works the same for PL/pgSQL functions.)
Use a proper JOIN
condition for better readability.
Simplify your query with table aliases.
Use the data type boolean
for widget_details.active_yn
.
I would advice to use true
/ false
instead of the string literals 't' / 'f' for data input into a boolean column. The manual:
The key words
TRUE
andFALSE
are the preferred (SQL-compliant) usage.
In a WHERE
clause, every expression is evaluated to a boolean
result. true
qualifies, false
or null
do not. For a boolean
type, simplify this:
AND d.active_yn = TRUE
to just:
AND d.active_yn
In order to use a custom composite type, you have to create it first with CREATE TYPE
.
Example, loosely based on your query (to be changed using the real datatypes):
CREATE TYPE widgetdetails AS (
id INT,
contact_id INT,
widget_details INT,
contact TEXT
);
Only after having created this type will this declaration be acceptable:
DECLARE
rec widgetdetails;
...
Also for the syntax of the CREATE FUNCTION
, stick to your first version, the second try has serious problems and won't help.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With