自动检查两个SQL查询在语义上是否相等

自动检查两个SQL查询在语义上是否相等,sql,Sql,我有两个问题: 'UPDATE foo SET bar = baz WHERE a = b AND c = d' 及 两者在语义上是相同的,但一个简单的比较会表明它们是不同的,因为第一个使用a=b和c=d,而第二个使用c=d和a=b 如何检查两个查询在语义上是否相等 这显然是一个简单的示例,可以通过对WHERE节点的语法树进行简单的字母排序来解决。我对一种通用的方法感兴趣,这种方法还可以解决更复杂的查询,甚至是子查询 另一个限制是我无权访问数据库,只能使用查询字符串。因此,运行查询是毫无疑问的

我有两个问题:

'UPDATE foo SET bar = baz WHERE a = b AND c = d'

两者在语义上是相同的,但一个简单的比较会表明它们是不同的,因为第一个使用a=b和c=d,而第二个使用c=d和a=b

如何检查两个查询在语义上是否相等

这显然是一个简单的示例,可以通过对WHERE节点的语法树进行简单的字母排序来解决。我对一种通用的方法感兴趣,这种方法还可以解决更复杂的查询,甚至是子查询

另一个限制是我无权访问数据库,只能使用查询字符串。因此,运行查询是毫无疑问的,因为它不会反映查询的平等性

上面粗体文本的示例如下:

可步行的:

A |  B |  C
1 | xx | xx
2 | yy | zz
FooTable':FooTable可在其他数据库上使用

A |  B |  C
1 | xx | xx
2 | ee | zz
3 | ss | xx
运行查询不会产生有效结果的示例:

1对同一数据库的查询:

两个查询的结果完全相同,但并不完全相同

包含不同数据库时的2个查询相同架构但不同数据:


这两个查询在语义上基本相同,但不会产生相同的结果。

这项任务确实不简单

本质上,您必须构建自己的查询解析器和优化器。这是optimizer的任务—转换执行计划中的查询运算符,以便在考虑所有约束的情况下,对于基础表中的任何可能数据,查询的最终结果保持不变。智能优化器能够为看起来非常不同的查询(如vs EXISTS中的查询)生成相同的计划,它们简化并统一WHERE子句中的逻辑条件,可以沿执行树推送谓词,并执行许多其他操作

从头开始编写这样的优化器会很困难,但您可以看看现有的开源数据库Postgres?看看你能不能从那里借点东西

另一种更实用的方法是利用现有数据库之一,而不是运行查询,让优化器返回生成的执行计划。然后,您可以比较执行计划,而不是比较原始SQL文本。如果计划相同,则原始查询是100%等效的。如果计划不同,那么优化器仍然可能不够聪明,无法推断查询是等价的,但您必须接受错误否定的可能性


我将查看几个不同的数据库,看看您可以使用内置功能从它们的优化器中获得什么样的信息。在任何情况下,生成的执行计划都应该比原始SQL文本更结构化,并且应该更容易自动比较它们。

当您说“检查”时,您是指自动检查还是手动验证?因此此查询使用In:select*from core。[Group]在ID从CORE中选择GroupID时,GroupPube应该等于使用这个选项:选择*from Cub。[Group]存在Cul.GroupListfrom CORE GroupPistase.GroupID= Cyr.[Group]。ID?@ Sim,那么我认为通过分析查询是不可能解决的。请考虑表T。考虑一个同义词S,它被应用到T或,如果你的数据库系统不支持同义词,一个视图V,它从T中选择所有列,不应用任何过滤器。仅仅通过检查两个查询无法确定它们是否相同,其中一个查询引用t,另一个查询引用s或v。@VladimirBaranov-通常有很多限制条件。您需要确保您是访问该数据库的唯一用户,您的查询不会修改数据,您不会面对恶意的系统管理员等。否则,有很多方法可以对两个相同的查询进行不同的优化。这听起来像是一个合理的选择。我将对此进行调查,如果证明可行,我将接受这一回答。目前的问题是,这更像是一个抽象的想法,而不是一个实际的解决方案,因此在没有验证的情况下接受它可能为时过早。我现在删除比较或赋值中的所有值,删除所有空白,然后按字母顺序排列语法树,最后比较字符串。到目前为止,这不是我最初想要的,但更简单,目前足以解决我的问题。但由于这是目前为止唯一的答案,听起来也不错,我接受这一点作为问题的答案。
A |  B |  C
1 | xx | xx
2 | ee | zz
3 | ss | xx
UPDATE FooTable SET B = 'rr' WHERE C = 'xx'
UPDATE FooTable SET B = 'rr' WHERE C = 'xx' OR B = 'ss'
SELECT A,B,C FROM FooTable where C = 'xx'
SELECT A,B,C FROM FooTable' where C = 'xx'