如何将Postgres函数结果用作DELETE查询中的单独列

时间:2019-02-16 13:22:58

标签: sql database postgresql postgresql-10

我必须基于其中一个列上的超长函数应用程序的多次比较删除表中的行。为了更详细,我将从base64解码,创建一个子字符串,转换为json,接受一个特定字段,然后将其转换为inet

我正在使用这些ip与我的WHERE子句中的其他ip /掩码进行比较。

我遇到的问题是获得实际结果是一个很长的字符串,如果我最后说ip < foo(bar(baz(quux))) OR ip2 < foo(bar(baz(quux))),那么用于比较的值也将最终被多次计算。

我正在寻找一种方法来预先计算该值,为其分配一个有意义的名称,然后在我的WHERE子句中使用该名称。

谢谢

2 个答案:

答案 0 :(得分:2)

您可以使用横向连接:

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);

答案 1 :(得分:1)

您是否考虑过使用CTE

例如,假设我们有下表

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

假设我们要删除表达式结果所在的所有行

  

some_data%10

是(> = 1和<= 4)或(> = 6和<= 8)。

在这种情况下,模运算将您的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);

正如您所说,这将多次重新计算同一件事。为了只进行一次计算,我们可以创建一个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部分中使用预先计算的列。