问题
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.
回答1:
The syntax you are trying to use is foreign to Postgres.
Your code is much more complicated than it needs to be. Use a simple SQL function:
CREATE OR REPLACE FUNCTION get_details_for_widget(widgetid integer)
RETURNS TABLE (id int, contact_id int, priority int, contact text)
$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$ LANGUAGE sql
You don't need plpgsql at all for such a simple function. Use a plain SQL function instead.
Define an ad-hoc row type with RETURNS TABLE (). I improvised with the column types since you did not provide your table definitions. This works for plpgsql functions just as well.
Also:
Use a proper JOIN condition for better readability.
Simplify your query with table aliases.
Use the data type boolean for
widget_details.active_yn.
Boolean values
As clarified in the comment, it's a boolean column already. I would advice to use TRUE / FALSE instead of the string literals 't' / 'f' for data input - quoting the manual about the boolean type:
The key words
TRUEandFALSEare the preferred (SQL-compliant) usage.
In a WHERE clause, every expression is evaluated to a boolean result. TRUE qualifies, FALSE or NULL do not. So, for a boolean type, you can simplify:
AND d.active_yn = TRUE
to just:
AND d.active_yn
回答2:
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.
来源:https://stackoverflow.com/questions/17529917/declare-and-return-a-custom-type-in-postgresql-function