Like @Abelisto commented, you cannot refer to SELECT
list expressions from the WHERE
(or JOIN
) clause of the same command because expressions in the WHERE
clause are evaluated first. Consider the sequence of events:
You need a subquery or CTE to avoid repeating the expression. However, your expressions are not exactly the same to begin with. You extract a simple text as json
and use the same as actual text
in the JOIN clause. The extraction is tricky by itself. Consider:
test=# SELECT json '"foo"' #>> '{}';
?column?
----------
foo
#>>
is the operator to ...
Get JSON object at specified path as text
Passing an empty array as path ({}
) extracts text
from the simple json
text. Related:
Now, to avoid repeating the extract path, extract state
in the CTE or in a subquery and apply the above expression in the outer SELECT
:
SELECT DISTINCT ON (a.place_id)
a.state
, a.full_json -> 7 -> 'long_name' AS postal_code
, a.full_json #> '{3,short_name}' AS city -- alternative syntax, btw.
FROM (
SELECT full_json -> 5 -> 'short_name' AS state -- once!
, full_json
FROM addresses_autocomplete
WHERE json_array_length(full_json) > 7
AND formatted = $1
) a
JOIN regions r ON r.short_name = t.state #>> '{}' -- key element!
WHERE r.country_id = 1
-- ORDER BY place_id, ??? -- put expression(s) here to get deterministic pick
Equivalent to your original. While being at it I simplified the query, inlined the CTEs (don't use CTEs unless needed before Postgres 12, they typically add cost) and added ORDER BY
, which will be required to get a deterministic result.
About DISTINCT ON
& ORDER BY
:
But are you sure you want postal_code
, city
and state
as type json
? That's an odd requirement.
Also, the above query may not produce the best query plan. The key to performance is to support the most selective predicates with optimal indexes. Repeating an expression hardly matters. You might want this instead:
SELECT DISTINCT ON (a.place_id)
a.full_json #>> '{5,short_name}' AS state
, a.full_json #>> '{7,long_name}' AS postal_code
, a.full_json #>> '{3,short_name}' AS city
FROM addresses_autocomplete a
JOIN regions r ON r.short_name = a.full_json #>> '{5,short_name}' -- back to repeating
WHERE a.formatted = $1
AND json_array_length(a.full_json) > 7
AND r.country_id = 1
-- ORDER BY a.place_id, ???