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 如何处理视图,但阻力最小的路径可能是将您的查询重写为仅使用 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)

【讨论】:

【参考方案2】:

PostgreSQL 不会将视图定义存储为字符串,而是将其解析为“节点树”并以这种方式存储。这样做的好处是视图不必每次都解析,它不受底层对象重命名的影响,并且可以跟踪对这些对象的依赖关系。

您的括号可能使语句更具可读性,但它们在语法上无关紧要,因此当 PostgreSQL 将节点树分解为 SQL 表达式时,它会省略它们。

【讨论】:

以上是关于PostgreSQL ALTER VIEW 重写更改和/或含义的主要内容,如果未能解决你的问题,请参考以下文章

postgresql: alter system

PostgreSQL ALTER TABLE 命令

PostgreSQL ALTER TABLE 命令

PostgreSQL ALTER TABLE 命令

13.PostgreSQL Alter,Truncate Table

ALTER TABLE,在非空列中设置空,PostgreSQL 9.1