oracle查询结果不一致

时间:2010-04-21 17:10:55

标签: sql oracle

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

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

这会返回单个结果'Testerson,Testy','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,新的DBA仍在加快速度,所以我试图调试这个问题。话虽这么说,请你比一位oracle专家更彻底地解释一下。

感谢

2 个答案:

答案 0 :(得分:1)

原来问题是一个冲突的索引。列上有一个旧索引,用于构建v_ssn虚拟列。我删除了该索引,查询开始按预期运行。我仍然担心该索引如何影响查询,但至少我的问题已解决。

感谢您的帮助!

答案 1 :(得分:0)

首先,你有一个加入 “AND od.orderno = oa.orderno”,这将抵消外部联接的 “oa.lrn(+)= tc.lrn_order”。也就是说,如果tc.lrn_order没有找到OA上一场比赛时,外部联接说仍然返回一行但将有一个空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在“tab”中不存在,第一个将返回0,第二个不返回任何行(并且使用外连接,将返回NULL)。

如果COL上有可用的索引,那么选项1可能很有吸引力。我怀疑甲骨文的地方重新写后者向前,如果,而不是NVL2,你只是简单地显示的has_garn值,你会看到一个0,而不是空。

该错误的替代方案可能是:

如果v_ssn基于func(col),那么Oracle可能(错误地)假设如果COL为null,则func(COL)必须为null。如果大部分COL为null,则可能会假设使用COL上的索引来查找非空行将为其提供更小,更高效的行进行处理。