Question

Here's the scenario. I'd like to return an ntiled result set depending on a record count. For instance:

DO
$BODY$
IF ( SELECT count(*) < 50 FROM (
SELECT * FROM ( SELECT col1, col2, col3 FROM v_my_view) AS cnt; )
THEN
SELECT * FROM ( SELECT col1, col2, col3 FROM v_my_view ) AS qry;
ELSE (
SELECT *, NTILE(5) OVER (ORDER BY col1 DESC) AS my_tile FROM (
SELECT col1, col2, col3 FROM v_my_view ) AS tileme; )
END IF;
END;
$BODY$

Please note, the syntax is approximate, but the intent should be obvious. If the record set is small, return the query else return an ntiled query. I've had various error messages trying to execute this, including:

cannot use RETURN QUERY in a non-SETOF function

or

query has no destination for result data

Also, I know that you're not supposed to use * in production code.

Was it helpful?

Solution

The problem is that you cannot return rows from a DO statement at all. You need to use a function with a declared RETURN type. To allow procedural elements, use LANGUAGE plpgsql (which is also the default for DO statements):

CREATE OR REPLACE FUNCTION foo()
  RETURNS TABLE(col1 text, col2 text, col3 text, my_tile int) AS
$func$
BEGIN

   IF (SELECT count(*) < 50 FROM v_my_view) THEN
      RETURN QUERY
      SELECT v.col1, v.col2, v.col3, 0 AS my_tile
      FROM   v_my_view v;
   ELSE
      RETURN QUERY
      SELECT v.col1, v.col2, v.col3, ntile(5) OVER (ORDER BY v.col1 DESC)
      FROM   v_my_view v;
   END IF;
END
$func$  LANGUAGE sql STABLE;

The data types in the RETURNS clause have to match your actual data types. Column aliases inside the query are not visible in the result, Instead, the declared names in the RETURNS clause are used.

Also, count(*) is perfectly fine syntax.

This could be replaced with a simple query and a CASE statement for the last column, though ...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top