2010-04-21 91 views
4

我有一个非常奇怪的问题,我有一个复杂的视图,当我查询特定列时返回不正确的数据。
下面有一个例如:oracle查询结果不一致

select empname 
     , has_garnishment 
from timecard_v2 
where empname = 'Testerson, Testy'; 

此返回单个结果 'Testerson,暴躁', 'N'

但是,如果我使用查询:

select empname 
     , has_garnishment 
from timecard_v2 
where empname = 'Testerson, Testy' 
and has_garnishment = 'Y'; 

此返回单结果'Testerson,Testy','Y'

第二个查询应该返回第一个查询的一个子集,但它返回一个不同的答案。

当我使用查询:

select empname 
     , has_garnishment 
from timecard_v2 
where empname = 'Testerson, Testy' 
and has_garnishment = 'N'; 

我没有得到任何结果

我已经解剖视图,并确定视图定义的这部分是哪里出了问题产生和存在的问题,即使我把sql定义作为一个直接查询来运行(注意,为了清楚起见,我删除了除了感兴趣部分外的所有select子句,在完整查询中需要所有连接的表):


SELECT 
    e.fullname empname , 
    NVL2(ded.has_garn, 'Y', 'N') has_garnishment 
FROM timecard tc , 
    orderdetail od , 
    orderassign oa , 
    employee e , 
    employee3 e3 , 
    customer10 c10 , 
    order_misc om, 
    (SELECT COUNT(*) has_garn, 
    v_ssn 
    FROM deductions 
    WHERE yymmdd_stop        = 0 
    OR (LENGTH(yymmdd_stop)      = 7 
    AND to_date(SUBSTR(yymmdd_stop, 2), 'YYMMDD') > sysdate) 
    GROUP BY v_ssn 
) ded 
WHERE oa.lrn(+) = tc.lrn_order 
AND om.lrn(+) = od.lrn 
AND od.orderno = oa.orderno 
AND e.ssn  = tc.ssn 
AND c10.custno = tc.custno 
AND e.lrn  = e3.lrn 
AND e.ssn  = ded.v_ssn(+) 

关于'ded'子查询的定义需要注意的一件事。 v_ssn字段是扣除表上的虚拟字段。

我不是软件开发人员的DBA,但我们最近失去了我们的DBA,新的仍在加快速度,所以我试图调试这个问题。这就是说,请解释一些更彻底的东西,然后你会为一位神谕专家。

谢谢

+1

DED子查询似乎可以使用某些格式和注释来帮助使其更易于支持。但我怀疑我的麻烦阅读SQL与这个问题有任何关系。为了获得更多信息,请尝试使用视图SQL语句并添加“empname ='Testerson,Testy'”限制器。你会得到什么结果? – Jay 2010-04-21 17:24:58

+1

我会感兴趣的看到执行计划的两个查询给出不一致的结果。在SQLPlus中,输入'set autotrace traceonly explain',然后执行查询。 – 2010-04-21 18:10:58

+1

我想知道当你输入第一个含有had_garnishment ='N'的查询时,你会得到什么 – MJB 2010-04-21 19:31:04

回答

1

原来这个问题是一个矛盾的索引。该列中有一个旧索引,即v_ssn虚拟列的构建。我放弃了该索引,查询开始按预期行事。我仍然关心该索引如何影响查询,但至少我的直接问题得到解决。

感谢您的帮助!

+2

那么,v_ssn是基于一个非确定性函数?这是我能想到的唯一解释,即删除索引可能会改变查询的结果。 – 2010-04-22 05:52:36

+0

你应该接受你自己的答案。 – APC 2010-04-22 07:08:16

0

首先,您有一个连接“AND od.orderno = oa.orderno”,它将取消“oa.lrn(+)= tc.lrn_order”上的外连接。 IE,如果tc.lrn_order没有在oa上找到匹配,则外部联接表示仍然返回一行,但是会有一个null orderno,这将与od无法匹配

其次,虚拟列的定义可能是相关的。如果删除索引解决了问题,那么它表明早期的计划使用索引。

第三,ded子查询看起来有点笨重。在表面上看,

SELECT COUNT(*) FROM tab WHERE COL=:val 

似乎非常相似

SELECT cnt FROM (SELECT COL, COUNT(*) FROM tab GROUP BY COL) WHERE COL=:val 

而且其中:VAL不“标签”的存在,首先将返回0的计数和第二韩元” t返回任何行(并且使用外连接,将返回NULL)。

如果在COL上有可用的索引,则选项1可能很有吸引力。我怀疑Oracle是在将前者重写为前者,而如果不是NVL2,而只是显示了has_garn的值,那么您会看到0而不是null。

了错误的另一种可能是这样的:如果v_ssn基于FUNC(COL)

,那么Oracle可能(错误地)假设FUNC(COL)必须为空,如果COL为null。如果大部分COL都为空,则可能会假定在COL上使用索引来查找非空行会给它一个更小且更有效的一堆行来处理。