Я нашел второй подход, не добавленный к первому ответу, так как он короче и отличается.Шаги следующие:
- Рассчитать все потенциальные сокращения для каждого имени, рекурсивно
SQL
select
col
, col as abbr
from tab
union all
select
col
, substr(abbr, 1, length(abbr)-1 ) as abbr
from potential_abbreviations a
where length(abbr) > 1
Результаты
col abbr
--- -------
AAA AAA
AAA AA
AAA A
...
Затем вычислите конфликты между сокращениями.Также следите за именем столбца, который привел к этому сокращению.Мы хотим сохранить только сокращения, которые не вызывают конфликтов, поэтому агрегат
min()
не имеет значения.
SQL
select
abbr
, count(*) as conflicts
, min(col) as best_candidate
from potential_abbreviations
group by abbr
having count(*) = 1
Результат
ABBR CONFLICTS BEST_CANDIDATE
------- --------- ---------------
AAAA 1 AAAAAA
AAAAA 1 AAAAAA
AAAAAA 1 AAAAAA
AAB 1 AABA
AABA 1 AABA
...
Наконец, сделайте левое соединение потенциальных сокращений с лучшими бесконфликтными кандидатами и просто используйте имя столбца, если не было бесконфликтного разрешения:
SQL
select
p.col as col
, nvl(min(c.abbr), p.col) as abbr
from potential_abbreviations p
left join conflict_free c on p.col = c.best_candidate
where c.conflicts = 1 or p.abbr = p.col
group by p.col
order by col, abbr
Полный SQL
with potential_abbreviations(col,abbr) as (
select
col
, col as abbr
from tab
union all
select
col
, substr(abbr, 1, length(abbr)-1 ) as abbr
from potential_abbreviations a
where length(abbr) > 1
)
, conflict_free as (
select
abbr
, count(*) as conflicts
, min(col) as best_candidate
from potential_abbreviations
group by abbr
having count(*) = 1
)
select
p.col as col
-- , c.best_candidate
, nvl(min(c.abbr), p.col) as abbr
-- , min(c.abbr) over (partition by c.best_candidate) shortest
from potential_abbreviations p
left join conflict_free c on p.col = c.best_candidate
where c.conflicts = 1 or p.abbr = p.col
group by p.col, c.best_candidate
order by col, abbr
Результат
COL ABBR
------- ----
AAA AAA
AAAAAA AAAA
AABA AAB
AB AB
AC1 AC
AD AD
BAAAA BA
BBAA BB
COL1 COL1
COL21 COL2
Скрипка SQL
Примечание: Для Postgresql рекурсивный CTE должен быть with recursive
в то время как Oracle там вообще не нравится слово recursive
.