with src as (
select naimen,
-- обрезаем хвост из банковских реквизитов
regexp_replace(
trim(naimen),
'[[:space:]]+(' ||
'[РP]/[СC]' ||
'|([[:alpha:]]+[[:space:]]+)?ОСБ' ||
'|В[[:space:]]+(ОПЕРУ|ПУШКИНСК)' ||
'|ТРАНЗИТНЫЙ|ДОП\.|НЕВЫЯСНЕНН' ||
'|Ф/АЛ|ФИЛИАЛ|КАШИРСКИЙ' ||
'|Г\.[[:space:]]*[[:alpha:]]' ||
').*$',
'', 1, 1, 'i'
) as clean_name
from sh.uch_vse
where naimen is not null
and length(naimen) between 5 and 300
),
norm as (
select clean_name,
-- 1 = название обрезано полем (длина 50) и хвост не вырезался
case when length(naimen) >= 50
and clean_name = trim(naimen) then 1 else 0 end as is_cut,
upper(trim(clean_name)) as r, -- для LLC, LTD и т.п.
-- верхний регистр, схлопнутые пробелы, латиница и 0 -> кириллица
translate(
regexp_replace(upper(trim(clean_name)), '[[:space:]]+', ' '),
'ABCEHKMOPTXY0',
'АВСЕНКМОРТХУО'
) as n
from src
),
cand as (
select /*+ materialize */
clean_name,
is_cut,
-- ключ для склейки дублей: только буквы и цифры
regexp_replace(n, '[^А-ЯЁA-Z0-9]', '') as k
from norm
where (
-- аббревиатуры
regexp_like(n,
'^(ООО|ОАО|ЗАО|ПАО|АО|НАО|ТОО|НКО|ФГУП|МУП|ГУП|ГБУ|ГКУ|ГАУ|АНО|ПК|СПК|КФХ|РПО|СНТ|ТСЖ|ЖСК|АКБ|КБ)([[:space:]"«„''‘’“”`<]|$)')
-- полные названия
or regexp_like(n,
'^(ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ|(ПУБЛИЧНОЕ |ЗАКРЫТОЕ |ОТКРЫТОЕ )?АКЦИОНЕРНОЕ ОБЩЕСТВО)([[:space:]"«„''‘’“”`<]|$)')
-- иностранные формы
or regexp_like(r,
'^(LLC|LTD|JSC|PJSC|INC|GMBH)([[:space:]"«„''‘’“”`<]|$)')
)
-- физлица с инициалами
and not regexp_like(clean_name, '^[А-ЯЁ][А-ЯЁа-яё-]+[[:space:]]+[А-ЯЁ]\.', 'c')
-- мусор с длинными номерами счетов
and not regexp_like(clean_name, '[0-9]{9,}')
-- банки (уберите строку, если банки нужны)
and not regexp_like(n, '(^|[[:space:]"«])(БАНК|АКБ|КБ)([[:space:]"»]|$)')
)
select min(c.clean_name) as "Наименование"
from cand c
where c.is_cut = 0
or not exists (
select 1
from cand x
where x.k like c.k || '_%'
)
group by c.k
order by 1;