Запрос на удаление «дубликатов» строк с помощью регулярных выражений - PullRequest
2 голосов
/ 20 мая 2019

Я использую PostgreSQL.У меня есть таблица keywords:

# Table name: keywords
#
#  id         :integer not null, primary key
#  text       :string  not null
#  match_type :string  not null
#  adgroup_id :integer not null

Таблица имеет индекс uniq USING btree (match_type, adgroup_id, text)

Теперь проблема в том, что для таких же adgroup_id и match_type есть тексты типа "Hello" и " Hello" или "Hello " или " Hello " (обратите внимание на начальные / конечные пробелы).Проблема в том, что столбец text содержит те пробелы в начале и конце строки, которые вызывают неверные данные (которые не прошли бы индекс uniq без этих пробелов).

Я планирую добавить пробелобрезка перед вставкой в ​​будущем, но сначала мне нужно очистить данные.

Как удалить «дубликаты» данных, оставив уникальные (на основе сравнения строк без опережающегои конечные пробелы)?

Ответы [ 2 ]

1 голос
/ 20 мая 2019

demo: db <> dbfiddle (пример содержит две группы: «Hello» без элемента без пробелов; «Bye» содержит два элемента без пробелов)

DELETE FROM keywords
WHERE id NOT IN (
    SELECT DISTINCT ON (trim(text))                 --1
        id
    FROM
        keywords
    ORDER BY 
        trim(text), 
        text = trim(text) DESC                   --2
)
  1. Группировка по обрезанным текстам.
  2. Порядок по урезанным текстам и информация, если текст без пробелов.Если есть один элемент, то он будет упорядочен первым и будет принят предложением DISTINCT ON.Если нет ни одного, будет взят другой элемент

Решение, содержащее дополнительные столбцы:

    DELETE FROM keywords
    WHERE id NOT IN (
        SELECT DISTINCT ON (match_type, adgroup_id, trim(text))
            id
        FROM
            keywords
        ORDER BY 
            match_type,
            adgroup_id,
            trim(text), 
            text = trim(text) DESC
    )
1 голос
/ 20 мая 2019

Вот один вариант, использующий CTE.CTE находит все (match_type, adgroup_id) группы, имеющие два или более text значения, которые совпадают с сокращением начальных и конечных пробелов.Мы также вычисляем следующее:

  • cnt - для каждой группы, сколько раз появляется «чистая» версия текста.Чистый здесь означает, что текст без начального или конечного пробела
  • rn - произвольный номер строки для каждой группы (match_type, adgroup_id), начиная со значения 1

Затем мы удаляем строку только в том случае, если она появляется в дублирующейся группе и либо она не является чистой версией текста (cnt > 0), либо номер произвольной строки больше единицы.Это означает, что для случаев "Hello " и " Hello" одна из этих двух записей будет произвольно удалена.Но если бы существовала третья «чистая» запись с "Hello", то она была бы сохранена, и оба из двух предыдущих случаев были бы удалены.

with cte as (
    select match_type, adgroup_id, trim(text) as text,
        count(case when text = trim(text) then 1 end) as cnt,
        row_number() over (partition by match_type, adgroup_id order by trim(text)) rn
    from keywords
    group by match_type, adgroup_id, trim(text)
    having count(*) > 1
)

delete
from keywords k1
where exists (select 1 from cte k2
              where k1.match_type = k2.match_type and
                    k1.adgroup_id = k2.adgroup_id and
                    k1.text <> k2.text and (k2.cnt > 0 or k2.rn > 1));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...