Я ищу ошибки в таблице и хочу сообщить как дубликаты, так и пропущенные значения. Я не уверен в лучшем способе сделать это и ищу совет относительно лучшего способа достигнуть этого. Это в Oracle 12c.
Похоже, что для достижения желаемого результата:
SELECT a.id,
a.mainfield,
a.location,
b.counter
FROM maintable a
INNER JOIN (
SELECT mainfield,
Count(*) counter
FROM maintable
GROUP BY mainfield
HAVING Count(mainfield) > 1 OR mainfield IS NULL
) b ON a.mainfield = b.mainfield OR
( a.mainfield IS NULL AND b.mainfield IS NULL )
ORDER BY a.mainfield;
Это работает и дает мне идентификатор, потенциально нулевое значение MAINFIELD, местоположение и количество либо дублированных значений MAINFIELD, либо нулевых значений MAINFIELD.
Есть ли что-то более простое или потенциально более эффективное, что я мог бы использовать? Я должен признать, что мои навыки SQL довольно ржавые.
Пример данных может помочь, а может и не помочь, но идентификатор является первичным ключом, является числом и не имеет значения NULL. Другие поля являются как NVARCHAR2, так и обнуляемыми. Ни один из них не проиндексирован. Вот как может выглядеть результат. Некоторые записи являются прямыми ошибками. Некоторые очевидные опечатки. Некоторые, похоже, являются тестовыми данными.
ID MAINFIELD LOCATION COUNTER
------- --------- --------------------------------- -------
16626 206000650 9A OLIVER ST CENTRAL STATION 2
18805 206000650 3 SWIFT CT CENTRAL STATION 2
22409 940000170 2 MARKET ST NEWARK DE 2
22003 940000170 1 MARKET ST NEWARK NJ 2
29533 970000030 95 MILL RD ANDOVER 2
20256 970000030 12 RAILROAD AVE 2
29018 978900050 44 BROAD STREET 2
28432 978900050 WASHINGTON ST AND HAMILTON AVE 2
21831 980700050 BROADWAY NEWTOWN 2
24147 980700050 MAIN STREET LEVITTOWN 2
26418 3
26738 TEST DATA 3
26755 3
Последние три строки имеют нулевое значение MAINFIELD, и таких записей три (две из которых также имеют нулевое местоположение).
После некоторого понимания приведенных выше данных я понял, что мог бы рассмотреть возможность использования NVL для устранения части условий, например так (при условии, что выбранное мной значение не будет действительным значением в основном поле):
SELECT a.id,
a.mainfield,
a.location,
b.counter
FROM maintable a
INNER JOIN (
SELECT mainfield,
Count(*) counter
FROM maintable
GROUP BY mainfield
HAVING Count(mainfield) > 1 OR mainfield IS NULL
) b ON NVL(a.mainfield,'***NULL***') = NVL(b.mainfield.'***NULL***')
ORDER BY a.mainfield;
Это выполняется немного быстрее и, кажется, дает желаемый результат. Я безуспешно пробовал другие варианты, так что это может быть лучшая альтернатива.
Одна альтернатива, от которой я отказался, которая могла бы подойти для немного другого сценария (но был для меня худшим исполнителем), это:
SELECT id,
mainfield,
location,
COUNT (id) OVER (PARTITION BY mainfield) counter
FROM maintable a
WHERE mainfield IS NULL
OR EXISTS(SELECT 1 from maintable b
WHERE mainfield = a.mainfield AND ROWID <> a.ROWID)
ORDER BY a.mainfield;
Мне просто очень понравилось, как все это сложилось, и я надеялся, что это будет несколько эффективно. Мы не говорим, что он работает в течение нескольких дней, но я пытаюсь заново изучить в Oracle то, что когда-то было навыком, когда я программировал с использованием SQL / DS.
Если что-то из вышеперечисленного дает кому-то идею лучшей альтернативы, я весь в ушах. (Например, есть ли способ указать счетчик [COUNT (id) для основного поля PARTITION BY] в предложении WHERE?)
Еще раз спасибо.