Сравните поля из результатов запроса в Oracle - PullRequest
0 голосов
/ 01 апреля 2019

Я нахожусь в сценарии, чтобы получить все записи из таблицы, где FIRSTNAME и LASTNAME определенной записи совпадают, но BIRTHDATE больше или равен 15 годам.

Считайте, что мой стол выглядит так:

_______________________________________________________________________________
| PRIMARY_ID | UNIQUE_ID | FIRSTNAME | LASTNAME | SUFFIX | BIRTHDATE          |
_______________________________________________________________________________
| 12345      | abcd      | john      | collin   | Mr     | 1975-10-01 00:00:00|
| 12345      | cdef      | john      | collin   | Mr     | 1960-10-01 00:00:00|
| 12345      | efgh      | john      | collin   | Mr     | 1975-10-01 00:00:00|
| 12345      | ghij      | john      | collin   | Mr     | 1960-10-01 00:00:00|
| 12345      | aaaa      | john      | collin   | Mr     | 1975-10-01 00:00:00|
| 12345      | bdfs      | john      | collin   | Mr     | 1975-10-01 00:00:00|
| 12345      | asdf      | john      | collin   | Mr     | null               |
| 12345      | dfgh      | john      | collin   | Mr     | null               |
| 23456      | ghij      | jeremy    | lynch    | Mr     | 1982-10-15 00:00:00|
| 23456      | aaaa      | jacob     | lynch    | Mr     | 1945-10-12 00:00:00|
| 23456      | bdfs      | jeremy    | lynch    | Mr     | 1945-10-12 00:00:00|
| 23456      | asdf      | jacob     | lynch    | Mr     | null               |
| 23456      | dfgh      | jeremy    | lynch    | Mr     | null               |
_______________________________________________________________________________

В этой таблице для PRIMARY_ID 12345 значения FIRSTNAME и LASTNAME одинаковы, но разница BIRTHDATE между UNIQUE_IDs составляет 15 лет. Так что этот PRIMARY_ID должен быть удален. При этом для PRIMARY_ID 23456 имя FIRSTNAME не одинаково для всех записей UNIQUE_ID, поэтому его не следует извлекать.

Таблица может содержать значения NULL для BIRTHDATE, которые следует игнорировать.

Это то, что я пробовал до сих пор:

SELECT
  /*PARALLEL(16)*/
  PRIMARY_ID,
  UNIQUE_ID,
  FIRSTNAME,
  LASTNAME,
  SUFFIX,
  BIRTHDATE,
  RANK() OVER ( ORDER BY FIRSTNAME, LASTNAME, SUFFIX, BIRTHDATE) "GROUP"
FROM TABLE;

Я попросил сформировать отдельные группы, чтобы различать по ИМЕНЕ ИМЕНИ, ИМЯ И ДЕНЬ РОЖДЕНИЯ. Я не знаю, что делать дальше.

Может кто-нибудь помочь, пожалуйста?

ПРИМЕЧАНИЕ : Поле BIRTHDATE имеет тип данных varchar, и я использую Oracle 12C.

1 Ответ

1 голос
/ 01 апреля 2019

Насколько я понимаю, цель состоит в том, чтобы вернуть отдельный набор 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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...