我有一个非常奇怪的问题,我有一个复杂的视图,当我查询特定列时返回不正确的数据 下面是一个例子:
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专家更彻底地解释一下。
感谢
答案 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上的索引来查找非空行将为其提供更小,更高效的行进行处理。