我遇到了EXISTS子句无法正常运行的查询。该查询甚至返回不存在匹配记录的项目的结果,似乎完全忽略了EXISTS。它过去运行正常,我认为麻烦是从Oracle 12.1升级到12.2后开始的。
下面是完整的查询(仅更改了表和列的名称以使它们更易读,但我保留了所有逻辑以防与之相关):
WITH FirstDateFilter AS (
SELECT ReferenceDate,
Type,
LAG(Type, 1, 0) OVER (ORDER BY ReferenceDate) AS PreviousType
FROM ReferenceDateTable
WHERE ItemId = :itemId
AND ReferenceDate <= :endDate
AND Type IN (:type1, :type2)
), SecondDateFilter AS (
SELECT ReferenceDate
FROM FirstDateFilter
WHERE ReferenceDate >= :startDate
AND ReferenceDate >= ( SELECT StartDate FROM StartDateTable WHERE ItemId = :itemId )
AND Type = :type1
AND PreviousType = :type1
)
SELECT ReferenceDate, Value
FROM ResultTable
WHERE ItemId = :itemId
AND EXISTS ( SELECT * FROM SecondDateFilter WHERE SecondDateFilter.ReferenceDate = ResultTable.ReferenceDate )
在处理了一些测试数据之后,我认为导致失败的(部分?)行是第二个WITH中的子查询AND ReferenceDate >= ( SELECT StartDate FROM StartDateTable WHERE ItemId = :itemId )
。
我发现以下任何修改都会导致EXISTS再次按预期工作:
( SELECT ReferenceDate FROM SecondDateFilter WHERE SecondDateFilter.ReferenceDate = ResultTable.ReferenceDate )
放入SELECT ... FROM ResultTable
最后一个解决方案实际上解决了该查询的问题(技术上不一样,但是底层的业务逻辑检查出结果始终是相同的),但是我想知道EXISTS子句是否存在一般性问题(应该仅在Oracle 12.2中有效?)我应该注意。我还有很多查询可以利用它。
下面是一个复制错误的测试脚本。下面的查询按预期返回2行,但是删除注释行将得到5行。
CREATE TABLE ReferenceDateTable
(
ItemId number,
ReferenceDate date,
Type varchar2(1)
);
INSERT INTO ReferenceDateTable (ItemId, ReferenceDate, Type) VALUES (1, to_date('19000201', 'YYYYMMDD'), '1');
INSERT INTO ReferenceDateTable (ItemId, ReferenceDate, Type) VALUES (1, to_date('19000202', 'YYYYMMDD'), '1');
INSERT INTO ReferenceDateTable (ItemId, ReferenceDate, Type) VALUES (1, to_date('19000203', 'YYYYMMDD'), '2');
INSERT INTO ReferenceDateTable (ItemId, ReferenceDate, Type) VALUES (1, to_date('19000204', 'YYYYMMDD'), '1');
INSERT INTO ReferenceDateTable (ItemId, ReferenceDate, Type) VALUES (1, to_date('19000205', 'YYYYMMDD'), '1');
CREATE TABLE ResultTable
(
ItemId number,
ReferenceDate date,
Value number
);
INSERT INTO ResultTable (ItemId, ReferenceDate, Value) VALUES (1, to_date('19000201', 'YYYYMMDD'), 1);
INSERT INTO ResultTable (ItemId, ReferenceDate, Value) VALUES (1, to_date('19000202', 'YYYYMMDD'), 2);
INSERT INTO ResultTable (ItemId, ReferenceDate, Value) VALUES (1, to_date('19000203', 'YYYYMMDD'), 3);
INSERT INTO ResultTable (ItemId, ReferenceDate, Value) VALUES (1, to_date('19000204', 'YYYYMMDD'), 4);
INSERT INTO ResultTable (ItemId, ReferenceDate, Value) VALUES (1, to_date('19000205', 'YYYYMMDD'), 5);
CREATE TABLE StartDateTable
(
ItemId number,
StartDate date
);
INSERT INTO StartDateTable (ItemId, StartDate) VALUES (1, to_date('19000101', 'YYYYMMDD'));
WITH FirstDateFilter AS (
SELECT ReferenceDate,
Type,
LAG(Type, 1, 0) OVER (ORDER BY ReferenceDate) AS PreviousType
FROM ReferenceDateTable
WHERE ItemId = 1
AND ReferenceDate <= to_date('19000205', 'YYYYMMDD')
AND Type IN ('1', '2')
), SecondDateFilter AS (
SELECT ReferenceDate
FROM FirstDateFilter
WHERE ReferenceDate >= to_date('19000201', 'YYYYMMDD')
--AND ReferenceDate >= ( SELECT StartDate FROM StartDateTable WHERE ItemId = 1 )
AND Type = '1'
AND PreviousType = '1'
)
SELECT ReferenceDate, Value
FROM ResultTable
WHERE ItemId = 1
AND EXISTS ( SELECT * FROM SecondDateFilter WHERE SecondDateFilter.ReferenceDate = ResultTable.ReferenceDate )
;
答案 0 :(得分:3)
根据Jonathan's comments over on Twitter,建议的解决方法是在外部存在子查询中使用unnest
提示,因为该问题是由错误(可能是错误28319114)引起的。
[...]
SELECT ReferenceDate, Value
FROM ResultTable
WHERE ItemId = 1
AND EXISTS ( SELECT /*+ UNNEST */ * FROM SecondDateFilter WHERE SecondDateFilter.ReferenceDate = ResultTable.ReferenceDate )