【发布时间】:2021-05-20 21:14:30
【问题描述】:
我们在 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 在重写期间破坏视图(我认为这是不可避免的)?
谢谢
【问题讨论】:
-
"删除了一堆括号,这大大改变了 AND / OR 的含义" - 不,它没有。 AND 绑定比 OR 更强,这些查询在语义上仍然是等效的(即使第二个可能不太可读)。 “这些查询不会产生相同的结果。” - 你确定吗?