When is SELECT necessary in PL/pgSQL functions?
-
27-12-2020 - |
Question
While assigning the result of a function or expression to a variable in PL/pgSQL, when is it necessary to use a SELECT
statement (sub-query)?
This may be just my misconception from SQL. I thought that everything should be enclosed in a (SELECT ...)
(even if it just involves computing a number), e.g.
$$
DECLARE parts text[];
BEGIN
parts := (SELECT string_to_array(my_str,'_') );
...
$$
but I just found that it works without the SELECT
:
parts := string_to_array(my_str,'_');
(It's almost as if I can use PL/pgSQL as if its Pascal.)
In general, what kind of expressions can be used directly without SELECT
in computing values?
Solution
This is only an educated guess.
It seems that the SELECT
is unnecessary because it's already present, e.g. in the implicit SELECT ... INTO
that an assignment :=
is equivalent to. From the documentation:
An assignment of a value to a PL/pgSQL variable is written as:
variable { := | = } expression;
As explained previously, the expression in such a statement is evaluated by means of an SQL SELECT command sent to the main database engine.
An example may be shown here, where:
name := (SELECT t.name from test_table t where t.id = x);
can also be written as
name := t.name from test_table t where t.id = x;
This seems possible because the second simplified form is equivalent to a SELECT INTO
in PL/pgSQL:
SELECT test_table.name INTO name FROM test_table WHERE id = x;
The first form would be equivalent to:
SELECT (SELECT t.name from test_table t where t.id = x) INTO name;
, which has a redundant layer of SELECT
that can be removed.
On the other hand, when an implicit SELECT
is not present, an explicit SELECT
seems necessary. For example, the same function cannot be used directly (i.e. without SELECT
)
string_to_array(my_str,'_');
if it's not in an assignment to a variable.
OTHER TIPS
Short answer every expression is a select statement.
https://www.postgresql.org/docs/10/static/plpgsql-expressions.html
All expressions used in PL/pgSQL statements are processed using the server's main SQL executor.
That means you can have from clauses and the like in assignments and after if statements.
IF count(*) > 10 FROM foo_table GROUP BY ORDER BY count(*) DESC LIMIT 1
THEN
-- handle the case when there exists a y group larger than 10