WITH
src AS ( -- дедуп до тяжёлых regexp'ов
SELECT DISTINCT NAIMEN
FROM SH.UCH_VSE
WHERE NAIMEN IS NOT NULL
),
norm AS (
SELECT
REGEXP_REPLACE(TRIM(NAIMEN), '[[:space:]]+', ' ') AS NAIMEN,
' ' || TRIM(REGEXP_REPLACE(UPPER(NAIMEN), '[^А-ЯЁ0-9-]+', ' ')) || ' ' AS TOK
FROM src
),
clean AS ( -- отсев организаций по токенам
SELECT n.NAIMEN
FROM norm n
WHERE NOT EXISTS (
SELECT 1
FROM SH.FIO_STOP s
WHERE (s.MATCH_TYPE = 'WORD' AND INSTR(n.TOK, ' ' || s.WORD || ' ') > 0)
OR (s.MATCH_TYPE = 'PREFIX' AND INSTR(n.TOK, ' ' || s.WORD) > 0)
)
),
t AS (
SELECT REGEXP_SUBSTR(
-- вырезаем ИП/ЧП/КПП 123/ИНН-цифры и т.п. в начале
REGEXP_REPLACE(NAIMEN,
'^((КПП|ПБОЮЛ|ИП|ЧП|ФЛ|ИНДИВИДУАЛЬН[А-ЯЁ]*|ПРЕДПРИНИМАТЕЛЬ[А-ЯЁ]*|[0-9]+) )+',
'', 1, 1, 'i'),
'^[А-ЯЁ][-А-ЯЁ]+'
|| '( [А-ЯЁ]\.? ?[А-ЯЁ]\.' -- Иванов И.И.
|| '| [А-ЯЁ][-А-ЯЁ]+( [А-ЯЁ][-А-ЯЁ]+)?' -- Иванов Иван (Иванович)
|| '( (ОГЛЫ|ОГЛУ|КЫЗЫ|УГЛИ|УУЛУ|ГИРЕЙ|ХАН|БЕК|БАЙ))?)',
1, 1, 'i') AS FIO
FROM clean
),
f AS (
SELECT DISTINCT FIO
FROM t
WHERE FIO IS NOT NULL
AND REGEXP_LIKE(FIO, '^[А-ЯЁ]', 'c')
AND LENGTH(FIO) BETWEEN 6 AND 40
AND LENGTH(REGEXP_SUBSTR(FIO, '^[^ ]+')) > 3 -- вместо {2,3} caps
AND REGEXP_LIKE(UPPER(REGEXP_SUBSTR(FIO, '^[^ ]+')),
'(ОВ|ЕВ|ЁВ|ИН|ЫН|ИЙ|ЫЙ|ОЙ|ЯН|ЯНЦ|ЕЦ|ЕНОК|ИЧ|УК|ЮК|АК|ЯК|ИК|ХАН|БЕК|БАЙ|[АЕИОУЮЯ])$')
)
SELECT COUNT(*) OVER () AS Всего_строк, FIO
FROM f
ORDER BY FIO;