BonBonSlick
@BonBonSlick
Junior Web Developer Trainee

Схлопывание одинаковых последовательных символов строки в один как пробелы в HTML?

Пример записи в БД
User -> name -> vasyyyaaaaaa
Пример запроса поиска по имени
Найти юзер с именем : vasya

При поиске fuzzy match и использовании pg_tgrm запрос vasya имеет высокий % разницы строк. Но если схлопнуть имя юзера до приемлемого
vasyyaa
и сравнить с
vasya
% одинаковости будет в разы выше.

Так вот, как это провернуть схлопывание в SQL запросе и програмно до определенного количества символов, услов с vasyyyaaaaaa трансформировать в vasya потому что количество одинаковых последовательых символов более 3-х+. 2 одинаковых подряд дозволено иметь.
  • Вопрос задан
  • 59 просмотров
Пригласить эксперта
Ответы на вопрос 1
@alexalexes
select string_agg(c.letter, '') as result
from (select b.letter, lag(b.letter) over (order by rownum) letter_before
        from (select row_number() over () as rownum, letter
                from (select unnest(string_to_array('vvvvvaassssyyyaaaaaaa', null)) as letter) as a
              ) as b
      ) as c
where c.letter_before is null or c.letter <> c.letter_before

Можно сделать функцию получения уникальной последовательности символов без повторения в SQL.
Запрос имеет следующие шаги:
a) Получение выборки строк посимвольным разбиением слова.
b) Выборка b содержит нумерацию символов rownum.
c) С помощью функции lag и колонки rownum (для выбора направления сортировки) получаем предыдущий символ слова в текущей строке.
d) Выбираем только те строки, которые содержат разные предыдущие символы и собираем символы обратно в строку result.
Усовершенствованный вариант:
select d.user_id, string_agg(d.letter, '') as result
from (select c.*, case when c.letter_before is null or c.letter_after is null or c.letter <> c.letter_before or c.letter <> c.letter_after then 1 else 0 end marker 
from
(select b.user_id, b.rownum, b.letter, lag(b.letter) over (partition by b.user_id order by b.rownum) letter_before, lead(b.letter) over (partition by b.user_id order by b.rownum) letter_after
        from (select a.user_id, row_number() over (partition by a.user_id) as rownum, a.letter
                from (select 1 user_id, unnest(string_to_array('vasyyyaaaaaa', null)) as letter
                      union all
                      select 2 user_id, unnest(string_to_array('pettyaaaa', null)) as letter
                     ) as a
              ) as b
 ) c
order by c.user_id, c.rownum) d
where d.marker = 1
group by d.user_id

a) Содержит 2 пользователя.
b) Добавлено слежение за передним символом lead.
с) marker дает 1 в случае "головы" или "хвоста" одинаковой последовательности символов.
d) из последовательности символов достается только голова или хвост последовательности (при наличии), что дает ограничение <3 повторений.
На всех уровнях использование оконных функций позволяет получать значения функций в пределах user_id.
PS: Данное решение демонстрирует, что можно работать в пределах стандартного синтаксиса SQL без использования хранимых процедур (с финтами ушами в виде оконных функций), но это не значит, что решение оптимально, возможно, стоит написать хранимку, с использованием классических циклов с курсорами по разбивке имени пользователя на символы.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы