Насколько я понимаю, цель состоит в том, чтобы вернуть отдельный набор primary_id
, для которого смежные (в алфавитном порядке) unique_id
, которые имеют одинаковые firstname
и lastname
, разделены на 15+ лет. Насколько я понимаю, NULL
должно прерывать сравнение (и считаться несовпадающим (в противном случае primary_id 23456 также будет соответствовать здесь для псевдосмежных bdfs
+ ghij
).
Есть и другие способы сделать это, но один из доступных в 12c способов - использовать сопоставление с образцом. Пример ниже. В примере просто используется разница в 5478 дней для представления 15-летнего периода, но можно заметить нюанс, что, если требуется большая точность для промежуточных дней и т. Д.
SELECT DISTINCT PRIMARY_ID
FROM THE_TABLE
MATCH_RECOGNIZE (
PARTITION BY PRIMARY_ID
ORDER BY UNIQUE_ID
ONE ROW PER MATCH
AFTER MATCH SKIP PAST LAST ROW
PATTERN(FIFTEEN_DIFF)
DEFINE FIFTEEN_DIFF AS
(FIFTEEN_DIFF.FIRSTNAME = PREV(FIFTEEN_DIFF.FIRSTNAME)
AND FIFTEEN_DIFF.LASTNAME = PREV(FIFTEEN_DIFF.LASTNAME)
AND (ABS(EXTRACT( DAY FROM (TO_TIMESTAMP(FIFTEEN_DIFF.BIRTHDATE,'YYYY-MM-DD HH24:MI:SS') - PREV(TO_TIMESTAMP(FIFTEEN_DIFF.BIRTHDATE,'YYYY-MM-DD HH24:MI:SS'))))) >= 5478)));
Result:
PRIMARY_ID
12345
1 row selected.
Приведенный выше запрос выполняет следующие действия:
PARTITION
с, чтобы посмотреть на каждую PRIMARY_ID
группу в отдельности,
затем ORDER
с UNIQUE_ID
, поэтому сравниваются только алфавитно-смежные записи.
Затем каждая запись сравнивается с последней, и если они разделяют FIRSTNAME
и LASTNAME
, а их BIRTHDATE
отличаются на 15+ лет, они считаются MATCH
и возвращают одну запись указать это.
После того, как любое совпадение найдено, оно переходит к следующему ряду и возобновляет сравнение.
Поскольку желательны только разные совпадения, в оператор выбора включается DISTINCT
.
EDIT:
В ответ на дополнительные вопросы добавьте два дополнительных примера.
Альтернатива 1: предварительный фильтр NULL
Это принесет различные UNIQUE_ID
в близость, давая различные совпадения.
SELECT DISTINCT PRIMARY_ID
FROM (SELECT PRIMARY_ID, UNIQUE_ID, FIRSTNAME, LASTNAME, SUFFIX, BIRTHDATE
FROM THE_TABLE
WHERE BIRTHDATE
IS NOT NULL)
MATCH_RECOGNIZE (
PARTITION BY PRIMARY_ID
ORDER BY UNIQUE_ID
ONE ROW PER MATCH
AFTER MATCH SKIP PAST LAST ROW
PATTERN (FIFTEEN_DIFF)
DEFINE FIFTEEN_DIFF AS
(FIFTEEN_DIFF.FIRSTNAME = PREV(FIFTEEN_DIFF.FIRSTNAME)
AND FIFTEEN_DIFF.LASTNAME = PREV(FIFTEEN_DIFF.LASTNAME)
AND (ABS(EXTRACT(DAY FROM (TO_TIMESTAMP(FIFTEEN_DIFF.BIRTHDATE , 'YYYY-MM-DD HH24:MI:SS') -
PREV(TO_TIMESTAMP(FIFTEEN_DIFF.BIRTHDATE , 'YYYY-MM-DD HH24:MI:SS'))))) >= 5478)));
Результат (теперь включает PRIMARY_ID
23456, поскольку удаление NULL приводит к порядку UNIQUE_ID
с разницей в 15+ лет):
PRIMARY_ID
12345
23456
2 rows selected.
Альтернатива 2: считать NULL как совпадение
SELECT DISTINCT PRIMARY_ID
FROM THE_TABLE
MATCH_RECOGNIZE (
PARTITION BY PRIMARY_ID
ORDER BY UNIQUE_ID
ONE ROW PER MATCH
AFTER MATCH SKIP PAST LAST ROW
PATTERN (FIFTEEN_DIFF)
DEFINE FIFTEEN_DIFF AS
(FIFTEEN_DIFF.FIRSTNAME = PREV(FIFTEEN_DIFF.FIRSTNAME)
AND FIFTEEN_DIFF.LASTNAME = PREV(FIFTEEN_DIFF.LASTNAME)
AND ((ABS(EXTRACT(DAY FROM (TO_TIMESTAMP(FIFTEEN_DIFF.BIRTHDATE , 'YYYY-MM-DD HH24:MI:SS') -
PREV(TO_TIMESTAMP(FIFTEEN_DIFF.BIRTHDATE , 'YYYY-MM-DD HH24:MI:SS'))))) >= 5478)
OR (LEAST(FIFTEEN_DIFF.BIRTHDATE,PREV(FIFTEEN_DIFF.BIRTHDATE)) IS NULL
AND COALESCE(FIFTEEN_DIFF.BIRTHDATE,PREV(FIFTEEN_DIFF.BIRTHDATE)) IS NOT NULL))));
Результат (Это также возвращает оба PRIMARY_ID
, так как NULL
теперь считается совпадением):
PRIMARY_ID
12345
23456
2 rows selected.