PostgreSQL version: 15
I have dynamic tables with dynamic columns and I need to calculate some abstract property length
. If column is array then I need to use array_length
function, if column is string then length
.
I tried to use CASE WHEN THEN
:
SELECT system_id
FROM models."model_e8467f0e-780d-45d0-b665-290452d0eae1"
WHERE (
(
SELECT CASE (SELECT element_type FROM elements WHERE id = '80bbc0ee-9f0b-4b16-9188-7d0b63c7c45d'::UUID)
WHEN 4 THEN length("element_80bbc0ee-9f0b-4b16-9188-7d0b63c7c45d")
WHEN 5 THEN array_length("element_80bbc0ee-9f0b-4b16-9188-7d0b63c7c45d", 1)
WHEN 6 THEN (
SELECT COUNT(child_id)
FROM m2m_entry_n_entry_element_values
WHERE parent_id = system_id
)
END
) >= 1
)
In this example, the column in the elements
table has element_type = 6
, so last branch should trigger. But function length(uuid[]) does not exist
error was raised, which means that postgres tried to calculate the first subexpression, although the documentation says the following:
A CASE expression does not evaluate any subexpressions that are not needed to determine the result.
2
Answers
Postgres goes through a multi-stage process before running the query. It may determine what each subexpressions is, even if it doesn’t call the functions in question. Postgres has to plan how it’s going to execute the query and what optimisations it can apply.
It’s probably a nicer strategy to notify you earlier, rather than forcing you to wait for a long running query before failing.
For details of what Postgres is doing, see it’s documentation here: https://www.postgresql.org/docs/current/overview.html
A statement is parsed before it is executed. Since the column
"element_80bbc0ee-9f0b-4b16-9188-7d0b63c7c45d"
seemd to be of typeuuid[]
(array ofuuid
), the parser complains that nolength()
function for that data type exists.This happens before the query even starts executing.
Your SQL statement has some fundamental problems and you get alerted to them early on.
Avoid using array types in column definitions, that usually leads to trouble.