Загрузка данных


WITH
stop_w AS (
    SELECT REPLACE(REPLACE(q'[ООО,ОАО,ПАО,ЗАО,АО,ОДО,ОСБ,АКБ,КБ,ГУП,ГУПУ,МУП,ФГУП,ФУ,КОРПОРЕЙШН,СОФТ,ИНТЕРНЭШНЛ,МЭП,ХОЗ-ВО,РУФПС,
ПАЛАТА,ОАНО,УЗЕЛ,КОНЦЕРН,ФОНД,БАНК,КОМПАНИЯ,ПРЕДПРИЯТИЕ,ОБЩЕСТВО,СОЮЗ,ВКЛАДЫ,ГРАЖДАН,КОРПОРАЦИЯ,КОРПОРАЦИИ,
ИНСТИТУТ,ПОДРАЗДЕЛЕНИЕ,СЕТИ,ОТД,МЕДИА,КЛУБ,РАЙПО,УСИБ,ОБЩ-ВО,ЕДИНЕНИЕ,СКАНСКА,ОТДЕЛЕНИЕ,ПОСОЛЬСТВО,ПОДВОРЬЕ,
КОНСУЛЬТАЦИЯ,СОВЕТ,ФИЛИАЛ,ЗАВОД,ОБЛПО,ГРУППА,СЧЕТ,РЕДАКЦИЯ,НПФ,ГП,ЧАСТЬ,РПЦ,ПИИ,ЭКСПЕДИЦИЯ,ГОСТИНИЦА,СНГ,
ПАРТИЯ,БЮРО,ЕДИНИЦА,Ф-Л,ТУРИЗМ,УМП,ДОМ,ТОВАРИЩЕСТВО,ФИН,РУПС,МЭИ,ЖСК,ТСЖ,ВДПО,ГМБХ,МИНФИН,МИНИФИН,РОС-Я,АРТЕЛЬ,
СИСТЕМС,СОДЕКСО,З-Д,Ф-Т,ЛИМИТЕД,ГОС,НЕФТЕБАЗА,ВЭИ,КОМБИНАТ,КООПЕРАТИВ,ДИСТАНЦИЯ,ЖИЛЬЕ,ЛИЦО,ЛИЦА,ХОЗЯЙСТВО,
УЧАСТОК,ШАХТА,ИСТЕРН,ПССП,ОТКРЫТОЕ,ЗАКРЫТОЕ,АКЦИОНЕРНОЕ,ГОРОД,ГОРОДА,ПО,МФ,ДОАО,ГПИНЖ,ПСЖА,ХОЗЯЙСТВО]', CHR(10)), CHR(13)) AS s
    FROM DUAL
),
stop_p AS (
    SELECT REPLACE(REPLACE(q'[НЕВЫЯСНЕ,ПАРТНЕР,ОБЪЕДИ,ОБЪЕД-,АДМИНИСТРА,УПРАВЛЕНИ,ДЕПАРТАМЕНТ,КОМИТЕТ,МИНИСТЕРСТВ,ПОЛИТИЧ,ПРЕДСТАВИТ,
ФЕДЕРАЛЬН,ГОСУДАРСТВЕНН,МЕЖДУНАРОДН,ОРГАНИЗАЦИ,ПРОИЗВОДСТВЕН,ПРОИЗВОД,РАЙОН,ПТИЦЕФАБРИК,ФАБРИК,ЗАКРЫТ,ОТКРЫТ,АКЦИОНЕРН,
МАШИНОСТРО,ГОРОДСК,СЕВЕРН,СЕВЕРО,ЮЖНО-,ЦЕНТР,ФИРМ,ГЛАВН,УПРАВ,ОБЩЕСТ,КОМПАНИ,МУНИЦИПАЛЬН,ДЕТСК,ТЕАТР,ТАНЦ,
ДЕЯТЕЛЬН,ОСУЩЕСТВ,ФЕДЕРАЦ,ПРОФСОЮЗ,ФИНУПР,СТАВРОПОЛЬСК,ЧАСОВЕНСК,БРОННИЦК,СТУПИНС,ОБЛАСТ,ДХООО,ШКОЛ,БОЛЬНИЦ,
ПОЛИКЛИНИК,ТОРГОВ,СТРОИТ]', CHR(10)), CHR(13)) AS s
    FROM DUAL
),
stop_all AS (
    SELECT /*+ MATERIALIZE */ W FROM (
        SELECT ' ' || TRIM(REGEXP_SUBSTR(s, '[^,]+', 1, LEVEL)) || ' ' AS W
        FROM stop_w CONNECT BY LEVEL <= REGEXP_COUNT(s, ',') + 1
        UNION ALL
        SELECT ' ' || TRIM(REGEXP_SUBSTR(s, '[^,]+', 1, LEVEL))
        FROM stop_p CONNECT BY LEVEL <= REGEXP_COUNT(s, ',') + 1
    )
),
src AS (
    SELECT DISTINCT NAIMEN
    FROM SH.UCH_VSE
    WHERE NAIMEN IS NOT NULL
    -- AND ROWNUM <= 20000          -- пробный прогон
),
norm AS (   -- верхний регистр, латиница->кириллица, чистка запятых и пробелов
    SELECT NAIMEN,
           TRIM(REGEXP_REPLACE(
               TRANSLATE(UPPER(NAIMEN), 'ABCEHKMOPTXY', 'АВСЕНКМОРТХУ'),
               '[,;[:space:]]+', ' ')) AS R
    FROM src
),
body AS (   -- вырезаем префиксы ЧП/ИП/НОТАРИУС/... из начала
    SELECT NAIMEN, R,
           REGEXP_REPLACE(R,
             '^((ЧАСТН[А-ЯЁ]*|ПРЕДПРИНИМАТЕЛ[А-ЯЁ]*|ПРЕДПР|ПР-ЛЬ|ПР-К|ИНДИВИД[А-ЯЁ]*|ИП|ЧП|ПБОЮЛ|ФЛ|НОТАРИУС|АДВОКАТ|КПП|[0-9]+)\.? )+',
             '') AS BODY
    FROM norm
),
s1 AS (
    SELECT NAIMEN, BODY,
           CASE WHEN BODY <> R THEN 1 ELSE 0 END AS HAS_PREF,
           CASE WHEN LENGTH(BODY) BETWEEN 5 AND 50 AND (
                  REGEXP_LIKE(BODY,
                     '^([А-ЯЁ][-А-ЯЁ]{2,}( [А-ЯЁ]\.( ?[А-ЯЁ]\.)?)'                      -- Иванов И.И.
                  || '|[А-ЯЁ]\. ?([А-ЯЁ]\. ?)?[А-ЯЁ][-А-ЯЁ]{2,}'                      -- И.И. Иванов
                  || '|[А-ЯЁ][-А-ЯЁ]{2,} [А-ЯЁ][-А-ЯЁ]+'                               -- Иванов Иван
                  ||   '( ([-А-ЯЁ]*(ИЧ|ВНА|ИЧНА)|[-А-ЯЁ]+ (ОГЛЫ|ОГЛУ|КЫЗЫ|УГЛИ|УУЛУ)))?)$')
               OR (BODY <> R AND REGEXP_LIKE(BODY, '^[А-ЯЁ][-А-ЯЁ]{2,}$'))              -- одна фамилия после префикса
                ) THEN 1 ELSE 0 END AS SHAPE_OK,
           REGEXP_SUBSTR(BODY, '[А-ЯЁ][-А-ЯЁ]{2,}') AS SURN,
           ' ' || TRIM(REGEXP_REPLACE(BODY, '[^А-ЯЁ0-9-]+', ' ')) || ' ' AS TOK
    FROM body
),
s2 AS (
    SELECT s1.*,
           CASE WHEN SHAPE_OK = 1 AND REGEXP_LIKE(SURN,
             '(ОВ|ЕВ|ЁВ|ИН|ЫН|ИЙ|ЫЙ|ОЙ|ЯН|ЯНЦ|ЕЦ|ЕНОК|ИЧ|УК|ЮК|АК|ЯК|ИК|ЫХ|ИХ|ХАН|БЕК|БАЙ|[АЕИОУЮЯ])$')
                THEN 1 ELSE 0 END AS END_OK
    FROM s1
),
res AS (
    SELECT NAIMEN, BODY AS FIO, SHAPE_OK, END_OK,
           CASE WHEN SHAPE_OK = 1 AND END_OK = 1
                THEN (SELECT MIN(TRIM(st.W)) FROM stop_all st WHERE INSTR(k.TOK, st.W) > 0)
           END AS STOP_WORD
    FROM s2 k
),
fin AS (
    SELECT NAIMEN, FIO, STOP_WORD,
           CASE WHEN SHAPE_OK = 0        THEN '2_НЕ_ФИО: форма'
                WHEN END_OK = 0          THEN '3_НЕ_ФИО: окончание фамилии'
                WHEN STOP_WORD IS NOT NULL THEN '4_НЕ_ФИО: стоп-слово'
                ELSE '1_OK' END AS STATUS
    FROM res
)
-- ВАРИАНТ 1: итоговый список ФИО
SELECT COUNT(*) OVER () AS Всего_строк, FIO
FROM (SELECT DISTINCT FIO FROM fin WHERE STATUS = '1_OK')
ORDER BY FIO;