首页 > 解决方案 > PostgreSQL ALTER VIEW 重写更改 AND/OR 含义

问题描述

我们在 PostgreSQL 中有一个大视图,它应该包含这个连接(更改名称以保护无辜者):

LEFT JOIN table1 ON
table4.a = table1.a AND
(regexp_split_to_array(table2.code::text, '_'::text))[1:2] = (regexp_split_to_array(table1.code::text, '_'::text))[1:2] AND
(
    table3.b = table1.b OR
    (table3.b IS NULL AND table1.b IS NULL) OR 
    (table3.b = 1 AND table1.b IS NULL) OR
    (table3.b IS NULL AND table1.b = 1)
) AND
(
    table3.c = table1.c OR 
    (table3.c IS NULL AND table1.c IS NULL) OR
    (table3.c = 1 AND table1.c IS NULL) OR
    (table3.c IS NULL AND table1.c = 1)
)

但是,当我们使用 CREATE OR REPLACE VIEW ... AS 保存视图定义时,它会重写它并删除一堆括号,这大大改变了 AND/OR 的含义:

LEFT JOIN table1 ON
table4.a = table1.a AND
(regexp_split_to_array(table2.code::text, '_'::text))[1:2] = (regexp_split_to_array(table1.code::text, '_'::text))[1:2] AND
(
    table3.b = table1.b OR
    table3.b IS NULL AND
    table1.b IS NULL OR 
    table3.b = 1 AND
    table1.b IS NULL OR
    table3.b IS NULL AND
    table1.b = 1
) AND
(
    table3.c = table1.c OR 
    table3.c IS NULL AND
    table1.c IS NULL OR
    table3.c = 1 AND
    table1.c IS NULL OR
    table3.c IS NULL AND
    table1.c = 1
)

这些查询不会产生相同的结果。

(数据来自第 3 方,其中表根据 a、b 和 c 中的数字连接,但如果 ID 为 1,则有时它为 NULL,因此 1 应与 NULL 匹配,反之亦然;它搞砸了,但我们不想更改数据)

所以本质上重写是改变视图的含义并有效地破坏它。

由于遗留软件冲突,我们被困在 9.4.26,所以我不确定问题是否仍然存在。

有什么方法可以防止 PostgreSQL 在重写期间破坏视图(我认为这是不可避免的)?

谢谢

标签: postgresqlpostgresql-9.4

解决方案


我不知道如何弄乱 Postgres 处理视图的方式,但阻力最小的路径可能是将您的查询重写为仅使用ANDs ,因此避免任何类型的括号恶作剧。就像是:

LEFT JOIN table1 ON
table4.a = table1.a
AND (regexp_split_to_array(table2.code::text, '_'::text))[1:2] = (regexp_split_to_array(table1.code::text, '_'::text))[1:2]
 AND   coalesce(table3.b, 1) = coalesce(table1.b, 1)
 AND   coalesce(table3.c, 1) = coalesce(table1.c, 1)


推荐阅读