PostgreSQL ALTER VIEW 重写更改和/或含义
Posted
技术标签:
【中文标题】PostgreSQL ALTER VIEW 重写更改和/或含义【英文标题】:PostgreSQL ALTER VIEW Rewrite Changes AND / OR Meaning 【发布时间】: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 更强,这些查询在语义上仍然是等效的(即使第二个可能不太可读)。 “这些查询不会产生相同的结果。” - 你确定吗? 【参考方案1】:我不知道 Postgres 如何处理视图,但阻力最小的路径可能是将您的查询重写为仅使用 AND
s,因此避免任何类型的括号恶作剧。比如:
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)
【讨论】:
【参考方案2】:PostgreSQL 不会将视图定义存储为字符串,而是将其解析为“节点树”并以这种方式存储。这样做的好处是视图不必每次都解析,它不受底层对象重命名的影响,并且可以跟踪对这些对象的依赖关系。
您的括号可能使语句更具可读性,但它们在语法上无关紧要,因此当 PostgreSQL 将节点树分解为 SQL 表达式时,它会省略它们。
【讨论】:
以上是关于PostgreSQL ALTER VIEW 重写更改和/或含义的主要内容,如果未能解决你的问题,请参考以下文章