动态SQL与from和where子句相同但不同的select子句一个工作而不是

时间:2016-04-02 18:50:28

标签: plsql oracle11g

我遇到了工作失败。在Job PLS中使用offcid和spool文件调用。我检查了假脱机文件错误无效的数字。通过传递offcid单独在PLS中运行查询时,我发现错误发生在一个选择查询中,其中offcid是在where子句中动态传递的。

where offcid = &2;

在进一步检查细节时,我发现还有一个相同的查询关于from和where子句只有select子句不同(没有group by)但运行正常。 offcid在作业中传递为43.根据高级开发人员的建议,我们扫描了表,发现在offcid列中有一个字符值,我们删除了源表中的一条记录,然后查询运行正常。

我只在dev中的生产环境中遇到此错误,同一场景下的相同查询运行正常。有谁知道可能导致这个问题的原因是什么? oracle 11g是否有任何可能导致此问题的后端检查?

1 个答案:

答案 0 :(得分:1)

所以offcid被定义为VARCHAR2而不是数字列?如果是这种情况,您可能希望将替换变量包装在引号中,以便传入的值也被视为字符。 (列是否应该被定义为数字列是另一回事。)

如果我理解你的问题,你想知道为什么一个环境在一个环境中遇到“无效数字”错误而不是另一个环境,假设两个环境都有相同的数据?

如果您尝试将字符串与数字进行比较,Oracle将隐式尝试将字符值转换为数字,并将结果与​​数字进行比较。就是这样:

SELECT * FROM dual WHERE '1' = 1 

实际上将被评估为:

SELECT * FROM dual WHERE TO_NUMBER('1') = 1

这里字符串'1'可以转换为数字,一切都很好。

在您的情况下,如果& 2被替换为10,则您的查询将被评估为:

SELECT ... where TO_NUMBER(offcid) = 10

即使表确实具有无法转换为数字的offcid值,也可以间歇性地获得“无效数字”错误的原因取决于Oracle是否实际考虑包含不可能的值的行转换为数字。这一切都取决于用于查询的执行计划。

假设您有这样的查询:

SELECT ... FROM some_table where TO_NUMBER(offcid) = 17 AND another_column = 4

让我们说你的违规行有offcid ='ONE7'而另一个_column = 2

如果Oracle对some_table执行全表扫描,它将比较所有行,当遇到具有无法转换为数字的值的行时(例如'XYZ'),您将遇到错误)。但是,如果你在另一个列上有一个索引,Oracle决定先使用another_column = 4来隔离行,那么它不会查看带有another_column = 2的行,也不会尝试将'XYZ'转换为数字,你不会得到错误。

可能有两个环境具有完全相同的数据且具有完全相同的查询,但是因为使用了不同的执行计划(已知数据库版本会导致优化器工作方式发生变化,可以影响查询计划)您的查询可以在一个环境中正常运行但在另一个环境中运行失败。

这有意义吗?