Версия с recursive subquery refactoring (КТР), которая требует 11gR2:
with t (last_name, first_name, orig_rn, part, part_length, remaining) as (
select last_name, first_name,
row_number() over (order by last_name, first_name),
cast (null as varchar2(20)), 0, length(first_name)
from t42
union all
select last_name, first_name, orig_rn,
part || substr(first_name, part_length + 1, 1),
part_length + 1,
remaining - 1
from t
where remaining > 0
),
u as (
select last_name, first_name, orig_rn, part, part_length,
count(distinct orig_rn) over (partition by last_name) as last_name_count,
count(distinct orig_rn) over (partition by last_name, part) as part_count
from t
),
v as (
select last_name, first_name, orig_rn, part, last_name_count,
row_number() over (partition by orig_rn order by part_length) as rn
from u
where (part_count = 1 or part = first_name)
)
select case when last_name_count = 1 then null
when part = first_name then first_name || ' '
else part || '. '
end || last_name as condendsed_name
from v
where rn = 1
order by orig_rn;
Что дает:
CONDENSED_NAME
----------------------------------------------
Johnson
Chris Roberts
Christ. Roberts
Alb. Smith
Alp. Smith
J. Smith
SQL Fiddle.
t
CTE рекурсивный. Она начинается с исходными строками таблицы и создает дополнительные строки для каждого возможного сжатия первого имени:
with t (last_name, first_name, orig_rn, part, part_length, remaining) as (
select last_name, first_name,
row_number() over (order by last_name, first_name),
cast (null as varchar2(20)), 0, length(first_name)
from t42
union all
select last_name, first_name, orig_rn,
part || substr(first_name, part_length + 1, 1),
part_length + 1,
remaining - 1
from t
where remaining > 0
)
select last_name, first_name, part
from t
where last_name = 'Johnson'
order by orig_rn, part_length;
LAST_NAME FIRST_NAME PART
-------------------- -------------------- ------------------------
Johnson Charles
Johnson Charles C
Johnson Charles Ch
Johnson Charles Cha
Johnson Charles Char
Johnson Charles Charl
Johnson Charles Charle
Johnson Charles Charles
Следующей КТР, u
(да, извините об именах, я невдохновленный) сравнивают значения по всем строк и подсчитывает вхождения. Все, что имеет значение 1
, уникально.
...
u as (
select last_name, first_name, orig_rn, part, part_length,
count(distinct orig_rn) over (partition by last_name) as last_name_count,
count(distinct orig_rn) over (partition by last_name, part) as part_count
from t
)
select last_name, first_name, part, last_name_count, part_count
from u
where last_name = 'Roberts'
order by orig_rn, part_length;
LAST_NAME FIRST_NAME PART LAST_NAME_COUNT PART_COUNT
-------------------- -------------------- ------------------------ --------------- ----------
Roberts Chris 2 2
Roberts Chris C 2 2
Roberts Chris Ch 2 2
Roberts Chris Chr 2 2
Roberts Chris Chri 2 2
Roberts Chris Chris 2 2
Roberts Christian 2 2
Roberts Christian C 2 2
Roberts Christian Ch 2 2
Roberts Christian Chr 2 2
Roberts Christian Chri 2 2
Roberts Christian Chris 2 2
Roberts Christian Christ 2 1
Roberts Christian Christi 2 1
Roberts Christian Christia 2 1
Roberts Christian Christian 2 1
Третий КТР v
смотрит только на уникальные из них, а затем ранжирует их по длине уникального значения; поэтому кратчайшее сокращение первого имени для записи, которая является уникальной для всех записей, оценивается как 1
.
...
v as (
select last_name, first_name, orig_rn, part, last_name_count,
row_number() over (partition by orig_rn order by part_length) as rn
from u
where (part_count = 1 or part = first_name)
)
select last_name, first_name, part, last_name_count
from v
where rn = 1
order by orig_rn;
LAST_NAME FIRST_NAME PART LAST_NAME_COUNT
-------------------- -------------------- ------------------------ ---------------
Johnson Charles 1
Roberts Chris Chris 2
Roberts Christian Christ 2
Smith Albert Alb 3
Smith Alphonse Alp 3
Smith Jason J 3
Затем окончательный запрос извлекает только тот ранг 1
, которые являются кратчайшими уникальными значениями, и форматирует их так, как вы хотели.
Если два человека имеют одно и то же имя, то оба из них полностью изложены (demo), которые, как представляется, вы хотите получить от вашего комментария.
Не уверен, что это действительно квалифицируется как «очиститель», за исключением того, что он только однажды ударяет по исходной таблице.
Интересно, но мне любопытно, как вы это сделаете программным. Если программная возможность возможна, SQL также возможен. Например, что, если есть два «Роберта Хаддока» и «Роб Хэддок», и по умолчанию вы обрезаете последние 3 буквы или как система будет создавать ник? –
Если два с тем же именем, то, я думаю, я просто вернусь к Роберту Хаддоку без периода. Если бы я хотел Роба Хэддока, он просто вернул Роба Хэддока, так как это его полное имя. Так что да, я думаю, мне нужно больше правил ... программно, он в настоящее время повторно запрашивает таблицу, добавляя одну букву к первому имени, пока не получит только возврат. Попытка избежать множественных вызовов sql. – jbrook10
Я получаю ваш программный подход. Не могли бы вы добавить еще некоторые данные образца и ожидаемый результат. Это поможет вам найти лучшие решения. –