我在一个我继承的应用程序中遇到了一个查询,如下所示:
Select * From foo where 1 <> 1
当我解析它时,它应该什么都不返回(1 <> 1
应该评估为false,对吧).但是(至少在我的Oracle盒子上)它会返回一个完整的所有内容列表foo
.当我在MSAccess/Jet和MSSQL中尝试相同的事情时,我得到了我期望的行为.为什么它与Oracle不同(为什么原始开发人员想要这样做)?
注意:我看到一些关于使用"where 1 = 1"的+ s和-s的迷信,它会导致全表扫描; 但我不认为这是原始开发者的意图.
小更新:
在这种情况下foo
是一个视图.当我在实际的桌子上尝试相同的事情时,我会得到我期望的(没有行).
更新2:
我已经在兔子洞的下方进一步遵循代码,并确定他正在做的只是尝试获取字段/列名称.我仍然不知道为什么它会返回完整的记录集; 但仅限于观点.
从字面上看,他正在用字符串构建查询并将其传递给另一个函数以便不加改变地执行.
'VB6 strSQL = "SELECT * FROM " & strTableName & " WHERE 1 <> 1"
在这种情况下,strTableName包含视图的名称.
更新3:
作为参考,这里是我遇到问题的一个视图(我已经更改了字段/表/模式名称)
CREATE OR REPLACE FORCE VIEW scott.foo (field1, field2, field4, field5, field12, field8, field6, field7, field16, field11, field13, field14, field15, field17 ) AS SELECT bar.field1, bar.field2, DECODE (yadda.field9, NULL, 'N', DECODE (yadda.field3, NULL, 'Y', 'N') ) AS field4, bar.field5, snafu.field6, DECODE (snafu.field6, NULL, bar.field8, bar.field8 - snafu.field6 ) AS field7, DECODE (yadda.field10, NULL, bar.field12, yadda.field10 ) AS field11, DECODE (SIGN ( yadda.field10 - bar.field12), NULL, 'N', 1, 'N', 0, 'N', -1, 'Y' ) AS field13, bar.field14, ADD_MONTHS (DECODE (yadda.field10, NULL, bar.field12, yadda.field10 ), bar.field14 * 12 ) AS field15, FROM clbuttic, bar, yadda, snafu WHERE clbuttic.asset_type = bar.asset_type AND bar.field16 = yadda.field9(+) AND bar.field1 = snafu.field1(+) AND (bar.field17 IS NULL) ;
追加Order By 1
(或者foo上的select中的一些列名)似乎说服Oracle给我回空集.这是一个长期解决方案,但不是短期解决方案(改变代码和重新部署是一个主要的PITA).我希望在数据库方面有一个鲜为人知的设置,或者视图中出现错误导致这种奇怪行为的原因.
好的......为什么在甲骨文中发生这种情况超出了我的想象.但是,我可以告诉你为什么它经常在其他数据库中使用:当人想要返回列时,但没有值.(例如为新表创建模式)
Oracle不会为我这样做:
SQL*Plus: Release 10.2.0.1.0 - Production on Thu Mar 19 13:36:20 2009 Copyright (c) 1982, 2005, Oracle. All rights reserved. Connected to: Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production SQL> select * from wrkr where 1 <> 1; no rows selected SQL> select count(*) from wrkr; COUNT(*) ---------- 88
编辑:它与观点无关,也是:
SQL> create view foo as select * from wrkr; View created. SQL> select count(*) from foo; COUNT(*) ---------- 88 SQL> select * from foo where 1 <> 1; no rows selected
当你想动态生成一个WHERE
子句.这样,您可以添加一些OR [another-condition]
子句并使其工作,而不检查条件是否是第一个.
它看起来像是Oracle优化器代码视图中的一个错误.我敢打赌你只能得到包含外连接的视图.你ORDER BY
解决了它,因为它实际上强迫了NO_MERGE
视图.
我不会在视图中放置一个ORDER BY
或一个NO_MERGE
提示,因为(取决于您的数据量)它可能会降低使用该视图的其他查询的性能.您应该在外部查询中添加no_merge提示:
Select /*+ NO_MERGE(foo) */ * From foo where 1 <> 1
您还应该在Oracle支持下提出SR,因为这绝对是一个错误.无论您从中选择什么,或者内部有多复杂,该查询都不应该返回任何行.永远不能.
我无法重现它,所以它可能已修复我正在使用的版本.您正在使用的db版本是什么?