Избегайте повторения выражения в списке SELECT и предложении WHERE - PullRequest
0 голосов
/ 28 сентября 2019

У меня есть базовый запрос, который выбирает строки из данных, выгруженных из автозаполнения Google, содержащих place_id, отформатированный адрес и столбец json, который содержит весь объект json.Я полагаю, что использую Postgres 10 или 11.

WITH 
    t AS (
        SELECT place_id,formatted,full_json 
        FROM addresses_autocomplete 
        WHERE json_array_length(full_json) > 7
    ), 
    r AS (
        SELECT short_name FROM regions WHERE regions.country_id = 1
    )
SELECT DISTINCT ON(place_id) 
    t.full_json->5->'short_name' AS state, 
    t.full_json->7->'long_name' as postal_code, 
    full_json->3->'short_name' AS city 
FROM t 
INNER JOIN r ON r.short_name = t.full_json->5->>'short_name' 
WHERE t.formatted=$1;

Есть ли способ написать мой запрос, чтобы t.full_json->5->'short_name' не повторялся?

1 Ответ

0 голосов
/ 29 сентября 2019

Как и @ Абелисто прокомментировал , вы не можете ссылаться на SELECT выражения списка из предложения WHERE (или JOIN) той же команды, потому что выражения в предложении WHERE вычисляются первыми,Рассмотрим последовательность событий:

Вам нужен подзапрос или CTE, чтобы избежать повторениявыражение. Однако , ваши выражения не совсем совпадают с самого начала.Вы извлекаете простой текст как json и используете то же самое, что и фактический text в предложении JOIN.Извлечение сложно само по себе.Обратите внимание:

test=# SELECT json '"foo"' #>> '{}';
 ?column?
----------
 foo

#>> является оператором для ...

Получить объект JSON по указанному пути в виде текста

Передача пустого массива в виде пути ({}) извлекает text из простого текста json.Похожие:

Теперь, чтобы избегать повторения путь извлечения, извлечение state в CTE или в подзапросе и применение вышеупомянутого выражения во внешнем SELECT:

SELECT DISTINCT ON (a.place_id)
       a.state
     , a.full_json -> 7 -> 'long_name'  AS postal_code
     , a.full_json <b>#> '{3,short_name}'</b>  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 = <b>t.state #>> '{}'</b>  -- key element!
WHERE  r.country_id = 1
-- ORDER  BY place_id, ??? -- put expression(s) here to get deterministic pick

Эквивалент вашего оригинала.В то же время я упростил запрос, выделил CTE (не используйте CTE, если они не нужны до Postgres 12, они обычно добавляют стоимость) и добавил ORDER BY, что потребуется для получения детерминированного результата.

О DISTINCT ON & ORDER BY:


Но вы уверены?Вы хотите postal_code, city и state как тип json?Это странное требование.

Кроме того, приведенный выше запрос может не дать наилучшего плана запроса.Ключом к производительности является поддержка наиболее селективных предикатов с оптимальными индексами.Повторение выражения вряд ли имеет значение.Вы могли бы хотеть это вместо этого:

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, ???
...