Как использовать результат функции postgres как отдельный столбец в запросе DELETE - PullRequest
0 голосов
/ 16 февраля 2019

Мне нужно удалить строки в таблице на основе нескольких сравнений с очень длинным приложением-функцией в одном из столбцов.Чтобы углубиться в детали, я декодирую из base64, делаю подстроку, преобразую в json, беру определенное поле, затем преобразую это в inet.

Я использую эти ips для сравнения с другими ips / масками в моем предложении WHERE.

Проблема, с которой я столкнулся, заключается в том, что получение фактического результата - довольно длинная строка, и если я в итоге скажу ip < foo(bar(baz(quux))) OR ip2 < foo(bar(baz(quux))), то это значение для сравнения также будет вычислено несколько раз.

Я ищу способ предварительно вычислить это значение, присвоить ему значимое имя, а затем использовать это имя в моем предложении WHERE.

Спасибо

Ответы [ 2 ]

0 голосов
/ 16 февраля 2019

Рассматривали ли вы использование CTE ?

Например, предположим, что у нас есть следующая таблица

CREATE TABLE test_table (
  id BIGINT PRIMARY KEY,
  some_data INTEGER
);

Допустим, мы хотимудалить все строки, в которых результат выражения

some_data% 10

равен (> = 1 и <= 4) или (> = 6 и <= 8).</p>

В этом случае операция по модулю заменяет ваш foo(bar(baz(column_name))) вызов операцией по модулю.

Простой подход заключается в написании следующего запроса:

DELETE FROM test_table
WHERE
  (MOD(some_data, 10) >= 1 AND MOD(some_data, 10) <= 4)
  OR
  (MOD(some_data, 10) >=6 AND MOD(some_data, 10) <= 8);

AsВы сказали, что это будет пересчитывать одно и то же несколько раз.Чтобы выполнить вычисление только один раз, мы можем создать CTE и использовать результат в запросе на удаление.

WITH precalculated_table AS (
  SELECT *, mod(some_data, 10) as mod_10_result FROM test_table
)
DELETE FROM test_table WHERE id IN (
    SELECT id from precalculated_table
  where
    (mod_10_result >= 1 and mod_10_result <= 4)
    OR
    (mod_10_result >= 6 AND mod_10_result <= 8)
);

Таким образом, мы выполняем вычисление только один раз, а затем используем предварительно вычисленный столбец.в WHERE части запроса DELETE.

0 голосов
/ 16 февраля 2019

Вы можете использовать боковое соединение:

select . . .
from t cross join lateral
     (values (foo(bar(baz(quux))) ) v(decoded_value)
where ip < v.decoded_vaue or ip2 < v.decoded_value;

В Postgres delete немного сложнее.Предполагая, что у вас есть первичный ключ:

delete t
using t t2 cross join lateral
     (values (foo(bar(baz(t2.quux))) ) v(decoded_value)
where t2.primary_key = t.primary_key and
      (t2.ip < v.decoded_vaue or t2.ip2 < v.decoded_value);
...