Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SELECT usage with the new CREATE PROCEDURE method

I'm trying to store a simple SELECT query with the new CREATE PROCEDURE method in PostgreSQL 11. My idea is to store the queries in the DB, because I can have a much simple code in my API server and maybe I don't need to develop a query builder if I can use if/else in an sql function with enforced type safety. I have this minimal example:

First I tried this plpgsql function:

CREATE OR REPLACE PROCEDURE test_proc() AS $$
    BEGIN
        SELECT * FROM my_db
        LIMIT 1;
    END;
$$ LANGUAGE plpgsql;

CALL test_proc();

However throws this error:

ERROR: query has no destination for result data HINT: If you want to discard the results of a SELECT, use PERFORM instead. CONTEXT: PL/pgSQL function test_proc() line 3 at SQL statement SQL state: 42601

If I trying to use RETURN QUERY:

CREATE OR REPLACE PROCEDURE test_proc() AS $$
    BEGIN
        RETURN QUERY;
        SELECT * FROM my_db
        LIMIT 1;
    END;
$$ LANGUAGE plpgsql;

I'm getting this error:

ERROR: cannot use RETURN QUERY in a non-SETOF function LINE 17: RETURN QUERY; ^ SQL state: 42804 Character: 310

I'm also getting error when I try to use RETURNS void AS $$ or RETURNS table(...) AS $$. Seems like RETURNS not supported in CREATE PROCEDURE? So, is it possible to return a table with the new stored procedure method? Or if it's not, maybe JSON?

like image 857
Lanti Avatar asked Aug 28 '18 19:08

Lanti


People also ask

Can procedure be used in SELECT statement?

We can not directly use stored procedures in a SELECT statement.

How can create or replace procedure in SQL?

Use the CREATE PROCEDURE command to create a stored procedure. Use CREATE OR REPLACE PROCEDURE to create a stored procedure or to update an existing procedure with a new return type, execution permissions, or procedure body.


1 Answers

Procedures in PostgreSQL (Oracle, DB2) are not same like procedures in MS-SQL. It has different target, and you cannot use it. Usually, the best what you can do, forgot all what you know from MSSQL. The procedural part is really different.

Only functions can returns some data - so you need to use functions. Functions can returns scalar value, composite value or array value, or table. You want function that returns table.

CREATE OR REPLACE FUNCTION fx()
RETURNS SETOF mytab AS $$
BEGIN
  RETURN QUERY SELECT * FROM mytab;
END
$$ LANGUAGE plpgsql;

SELECT * FROM fx();

For record:

You can use SQL function, that can have better (or worse) performance (depends on context). These functions are sometimes named as parametrized views.

CREATE OR REPLACE FUNCTION fx()
RETURNS SETOF mytab AS $$
  SELECT * FROM mytab;
$$ LANGUAGE sql;

Attention: this technique is antipattern!!! Don't do it. It is really not good idea. The functions should not to wrap queries. If you want to hide some complexity of queries, then use a views. Don't use a functions. Functions are effective barier for query optimizer, and when you use this antipattern, then optimizer cannot to well optimize any non trivial queries that use in this form evaluated subqueries.

Use it - if you want very very slow applications - or if your data model or queries are primitive. In other cases, don't do it.

Don't afraid of SQL - it is great language designed for manual usage. It is good to place all data access to one module (model), to don't access database everywhere in your code, but it is bad too hide SQL in your code.

like image 66
Pavel Stehule Avatar answered Sep 19 '22 16:09

Pavel Stehule