Я столкнулся с запросом, в котором предложение 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 )
После игры с некоторыми тестовыми данными, я думаю (частично?) ответственная строка за сбой - это подзапрос AND ReferenceDate >= ( SELECT StartDate FROM StartDateTable WHERE ItemId = :itemId )
во втором WITH.
Я обнаружил, что любое из следующих изменений приводит к тому, что EXISTS снова работает, как и ожидалось:
- JOIN ResultTable с SecondDateFilter (on ReferenceDate)
- Put
( SELECT ReferenceDate FROM SecondDateFilter WHERE SecondDateFilter.ReferenceDate = ResultTable.ReferenceDate )
в SELECT ... FROM ResultTable
- Закомментируйте подзапрос StartDateTable (больше не фильтрует эту таблицу, но в противном случае он работает снова)
- Переместите подзапрос StartDateTable в первый WITH
Последнее решение фактически решает мою проблему с этим запросом (технически не то же самое, но основная бизнес-логика проверяет, что результат всегда будетто же самое), но мне было интересно, если есть общая проблема с предложением 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 )
;