0

I'm trying to EXECUTE some SELECTs to use inside a function, my code is something like this:

DECLARE result_one record; BEGIN EXECUTE 'WITH Q1 AS ( SELECT id FROM table_two INNER JOINs, WHERE, etc, ORDER BY... DESC ) SELECT Q1.id FROM Q1 WHERE, ORDER BY...DESC'; RETURN final_result; END; 

I know how to do it in MySQL, but in PostgreSQL I'm failing. What should I change or how should I do it?

4
  • It's not obvious (to me at least) why you are using EXECUTE, or what results you expect from this query. There's no reason for the above code to even be in plpgsql - you could just use a SQL function Commented Nov 12, 2018 at 15:28
  • I know, the selects are examples, I need to know how to use the execute in this case. Those select has dynamic parameters, and some people will edit the parameters through CLI, long story. Commented Nov 12, 2018 at 15:30
  • Then you will need to give a more accurate example if you want people to figure out what your problem is. That code just isn't returning any results and I can't see why you would expect it to. You have read the relevant part of the manuals (postgresql.org/docs/11/…) haven't you? Commented Nov 12, 2018 at 15:43
  • Note that functions are distinct from procedures, so "stored procedure" (SP) is a misleading term when referring to a function. See: dba.stackexchange.com/a/194811/3684 Commented Nov 13, 2018 at 22:50

2 Answers 2

1

For a function to be able to return multiple rows it has to be declared as returns table() (or returns setof)

And to actually return a result from within a PL/pgSQL function you need to use return query (as documented in the manual)

To build dynamic SQL in Postgres it is highly recommended to use the format() function to properly deal with identifiers (and to make the source easier to read).

So you need something like:

create or replace function get_data(p_sort_column text) returns table (id integer) as $$ begin return query execute format( 'with q1 as ( select id from table_two join table_three on ... ) select q1.id from q1 order by %I desc', p_sort_column); end; $$ language plpgsql; 

Note that the order by inside the CTE is pretty much useless if you are sorting the final query unless you use a LIMIT or distinct on () inside the query.


You can make your life even easier if you use another level of dollar quoting for the dynamic SQL:

create or replace function get_data(p_sort_column text) returns table (id integer) as $$ begin return query execute format( $query$ with q1 as ( select id from table_two join table_three on ... ) select q1.id from q1 order by %I desc $query$, p_sort_column); end; $$ language plpgsql; 
Sign up to request clarification or add additional context in comments.

Comments

0

What a_horse said. And:

Plus, to pick a column for ORDER BY dynamically, you have to add that column to the SELECT list of your CTE, which leads to complications if the column can be duplicated (like with passing 'id') ...

Better yet, remove the CTE entirely. There is nothing in your question to warrant its use anyway. (Only use CTEs when needed in Postgres, they are typically slower than equivalent subqueries or simple queries.)

CREATE OR REPLACE FUNCTION get_data(p_sort_column text) RETURNS TABLE (id integer) AS $func$ BEGIN RETURN QUERY EXECUTE format( $q$ SELECT t2.id -- assuming you meant t2? FROM table_two t2 JOIN table_three t3 on ... ORDER BY t2.%I DESC NULL LAST -- see below! $q$, $1); END $func$ LANGUAGE plpgsql; 

I appended NULLS LAST - you'll probably want that, too:

If p_sort_column is from the same table all the time, hard-code that table name / alias in the ORDER BY clause. Else, pass the table name / alias separately and auto-quote them separately to be safe:

I suggest to table-qualify all column names in a bigger query with multiple joins (t2.id not just id). Avoids various kinds of surprising results / confusion / abuse.

And you may want to schema-qualify your table names (myschema.table_two) to avoid similar troubles when calling the function with a different search_path:

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.