有没有办法检查两个(非平凡的)选择是否等效?
最初我希望两个选择之间有形式上的等价,但是答案在 证明 sql-query-equivalency 阻止我。
对于我的实际需要,我可以检查两个选择的(实际)结果是否相同。
如果您想比较查询结果,请尝试以下操作:
(select * from query1 MINUS select * from query2)
UNION ALL
(select * from query2 MINUS select * from query1)
这将导致所有行仅由一个查询返回。
在标准 SQL 中你可以编写以下内容
(select * from query1 EXCEPT select * from query2)
UNION ALL
(select * from query2 EXCEPT select * from query1)
我想指出 MINUS 不是标准 SQL,所以我们需要使用 EXCEPT 来代替
对于
(select * from query1 EXCEPT select * from query2)
UNION ALL
(select * from query2 EXCEPT select * from query1)
我对
postgres 9.4
进行了一些尝试,这是我的结果。
[1] 不支持减号,因此需要使用
EXCEPT
正如@Bogdan 所说
[2] 仅使用
EXCEPT
不考虑重复,因此必须使用 EXCEPT ALL
[3]
EXCEPT ALL
要求结果中的列顺序应相同,因此
上面的查询 QUERY1
和 QUERY2
应该返回相同的列顺序,或者我们必须包装查询并确保列顺序相同。(可能会在应用程序逻辑中发生这种情况)
所以我认为,如果我们牢记以上三点,我们可以 100% 确定给定数据集上的两个查询返回的数据完全相同。
如果我遇到更多可能失败的边缘情况,将会更新。
运行两者并比较结果。使用 EXCEPT 操作从第二个查询返回的集合中减去第一个查询返回的集合。如果结果是空集那么它们是等价的。
此方法的问题在于它不能证明两个查询对于任何数据库都是等效的。这取决于您的数据库的内容。例如,如果您的数据库为空,则根据此方法,任何两个 select 语句都是等效的。
仅通过分析查询来证明等效性是一个未解决的问题 AFAIK(但我不完全是数据库理论大师,所以不要相信我;)) 另外,你可以看一下这个问题:Proving SQL 查询等价性
对我来说这成功了:
SELECT
BIN_TO_UUID(a.`parent_id`, true) shipmentId,
a.name,
a.company
FROM shipment_address a
EXCEPT
SELECT
BIN_TO_UUID(s.id, true) shipmentId,
s.name,
s.company
FROM shipment s
当它们相同时我得到零结果