你将如何证明两个查询在功能上是等价的,例如它们将始终返回相同的结果集。
由于我在做这个时遇到了一个特定的查询,我最终按照@dougman的建议,超过了大约10%的行表并对比结果,确保没有不合适的结果。< / p>
答案 0 :(得分:13)
您可以做的最好的事情是根据给定的输入集比较2个查询输出,寻找任何差异。要说它们总是会为所有输入返回相同的结果,这取决于数据。
对于Oracle,其中一个更好的方法(非常有效)就在这里( Ctrl + F 比较两个表的内容):
http://www.oracle.com/technetwork/issue-archive/2005/05-jan/o15asktom-084959.html
归结为:
select c1,c2,c3,
count(src1) CNT1,
count(src2) CNT2
from (select a.*,
1 src1,
to_number(null) src2
from a
union all
select b.*,
to_number(null) src1,
2 src2
from b
)
group by c1,c2,c3
having count(src1) <> count(src2);
答案 1 :(得分:9)
这听起来像是NP完全问题。我不确定是否有一种确定的方法来证明这种事情
答案 2 :(得分:4)
你应该检查珂赛特:它检查(带有证据)2个SQL查询是否相同,而不是等效的反例。这是绝对确定的唯一方法,差不多;)你甚至可以在他们的网站上输入2个查询并立即检查(正式)等价。
珂赛特链接: http://cosette.cs.washington.edu/
链接到可以很好地解释珂赛特如何工作的文章:https://medium.com/@uwdb/introducing-cosette-527898504bd6
如果你想要的只是一个快速的实用修复,你也可以检查这个stackoverflow答案: [sql - check if two select's are equal]
答案 3 :(得分:2)
这很容易做到。
让我们假设您的查询名为a和b
<强>一 减去 B'/强>
应该给你一个空集。如果没有。然后查询返回不同的集合,结果集显示不同的行。
然后做
<强> b 减去 一个强>
应该给你一个空集。如果是,则查询返回相同的集合。 如果它不为空,那么查询在某些方面是不同的,结果集会显示不同的行。
答案 4 :(得分:1)
DBMS供应商已经在很长一段时间内开展这项工作。正如Rik所说,它可能可能是一个棘手的问题,但我认为没有对问题空间的NP完整性进行任何形式分析。
但是,最好的办法是尽可能地利用您的DBMS。所有DBMS系统都将SQL转换为某种查询计划。您可以将此查询计划(查询的抽象版本)用作一个很好的起点(DBMS将进行大量优化,将查询展平为更可行的模型)。
注意:现代DBMS使用“基于成本”的分析器,该分析器在统计信息更新中是不确定的,因此随着时间的推移,查询计划程序可能会更改相同查询的查询计划。
在Oracle中(取决于您的版本),您可以告诉优化器使用SQL提示从基于成本的分析器切换到基于确定性规则的分析器(这将简化计划分析),例如
SELECT /*+RULE*/ FROM yourtable
基于规则的优化器自8i以来已被弃用,但它仍然会挂起甚至10g(我不知道'回合11)。但是,基于规则的分析器要复杂得多:错误率可能要高得多。
为了进一步阅读更通用的性质,IBM在查询优化专利方面相当丰富。这里有一个将SQL转换为“抽象计划”的方法,这是一个很好的起点: http://www.patentstorm.us/patents/7333981.html
答案 5 :(得分:1)
也许您可以使用Venn Diagrams(手动)绘制查询和结果,并查看它们是否生成相同的图表。维恩图适用于表示数据集,而SQL查询适用于数据集。绘制维恩图可能会帮助您可视化2个查询是否在功能上等效。
答案 6 :(得分:1)
这样就可以了。如果此查询返回零行,则两个查询将返回相同的结果。作为奖励,它作为单个查询运行,因此您不必担心设置隔离级别,以便数据在两个查询之间不会更改。
select * from ((<query 1> MINUS <query 2>) UNION ALL (<query 2> MINUS <query 1>))
这是一个方便的shell脚本:
#!/bin/sh
CONNSTR=$1
echo query 1, no semicolon, eof to end:; Q1=`cat`
echo query 2, no semicolon, eof to end:; Q2=`cat`
T="(($Q1 MINUS $Q2) UNION ALL ($Q2 MINUS $Q1));"
echo select 'count(*)' from $T | sqlplus -S -L $CONNSTR
答案 7 :(得分:0)
你没有。
如果您需要高度自信,例如,性能变化没有改变查询的输出,那么就测试它。
如果你需要非常高的信心......那么错误,再测试一下。
对于SQL查询来说,大量级别的测试并不难以拼凑。编写一个proc,它将迭代一大组/完整的可能参数集,并用每组参数调用每个查询,并将输出写入各自的表。比较两个表,你就可以了。
这不是完全科学的,我猜是OP的问题,但我不知道一种证明等效的正式方法。
答案 8 :(得分:0)
小心!功能“等价”通常基于数据,您可以通过比较许多情况 的结果来“证明”2个查询的等效性,并且一旦数据以某种方式发生变化仍然是错误的 < /强>
例如:
SQL> create table test_tabA
(
col1 number
)
Table created.
SQL> create table test_tabB
(
col1 number
)
Table created.
SQL> -- insert 1 row
SQL> insert into test_tabA values (1)
1 row created.
SQL> commit
Commit complete.
SQL> -- Not exists query:
SQL> select * from test_tabA a
where not exists
(select 'x' from test_tabB b
where b.col1 = a.col1)
COL1
----------
1
1 row selected.
SQL> -- Not IN query:
SQL> select * from test_tabA a
where col1 not in
(select col1
from test_tabB b)
COL1
----------
1
1 row selected.
-- THEY MUST BE THE SAME!!! (or maybe not...)
SQL> -- insert a NULL to test_tabB
SQL> insert into test_tabB values (null)
1 row created.
SQL> commit
Commit complete.
SQL> -- Not exists query:
SQL> select * from test_tabA a
where not exists
(select 'x' from test_tabB b
where b.col1 = a.col1)
COL1
----------
1
1 row selected.
SQL> -- Not IN query:
SQL> select * from test_tabA a
where col1 not in
(select col1
from test_tabB b)
**no rows selected.**