Mysql: объединить дубликаты данных, но игнорировать строку в дубликатах - PullRequest
0 голосов
/ 10 сентября 2018

Есть ли способ найти дубликаты данных, игнорируя заданную строку?

Например, если у меня есть таблица имен, есть ли способ объединить строки, которые имеют имя «Энн Смит», но игнорируют строку «Доктор».Например, строки, содержащие «Энн Смит» и «Доктор Энн Смит», должны объединяться в одну строку, которая принимает имя «Доктор Энн Смит».Если имена совпадают (за исключением строки «dr.») И адреса двух строк совпадают, объедините телефонные номера.Я хотел бы взять большее из двух имен, которое, я думаю, будет связано с использованием оператора MAX.

В настоящее время у меня есть таблица с именем t:

name          | phone      | address
ann smith     | 1234567899 | 123 home address
dr. ann smith | 1234567890 | 123 home address
brian smith   | 1235551234 | 789 city street

Я хочу получить:

name          | phone                  | address
dr. ann smith | 1234567890, 1234567899 | 123 home address
brian smith   | 1235551234             | 789 city street

Ответы [ 3 ]

0 голосов
/ 11 сентября 2018

Предполагая, что они точно вложенные, вы можете получить "длинную форму", выполнив:

select name,
       (select t2.name
        from t t2
        where t2.name like concat('%', t.name, '%')
        order by length(t2.name) desc
        limit 1
       ) as long_form
from t;

Затем вы можете использовать это в агрегации. Я бы использовал подзапрос:

select long_form, group_concat(distinct phone) as phones,
       group_concat(distinct address) as addresses
from (select t.*,
             (select t2.name
              from t t2
              where t2.name like concat('%', t.name, '%')
              order by length(t2.name) desc
              limit 1
             ) as long_form
      from t
     ) tt
group by long_from;
0 голосов
/ 12 сентября 2018

В итоге я воспользовался комбинацией вышеуказанных ответов. Сначала я создал временную таблицу, которая обрезает и заменяет 'Доктор 'строка с пустой строкой.

create temporary table if not exists temp_names AS (
select *, 
    case when name like lower('dr. %') then trim(replace(lower(name), lower('dr. %'), ''))
    else name end as plain_name from t);

Затем я использую select и group by для объединения значений в этой таблице с одним и тем же значением plain_name.

select max(name) as name, group_concat(distinct phone_number) as phone_number, address from temp_names 
    group by plain_name, address having count(*) >=1;

Это дает таблицу с желаемыми результатами:

name          | phone_number           | address
dr. ann smith | 1234567890, 1234567899 | 123 home address
brian smith   | 1235551234             | 789 city street
0 голосов
/ 10 сентября 2018

Чтобы сделать то, что вы хотите, вам, вероятно, потребуются CTE (Common Table Expressions) и LATERAL запросы. К сожалению, MySQL 5.x не реализует ни один из них.

Следующий запрос находит повторяющиеся имена:

select plain_name, count(*)
  from (
    select name, trim(replace(lower(name), lower('Dr.'), '')) as plain_name
      from my_table
  ) x
  group by plain_name
  having count(*) > 1

Это шаг в правильном направлении, но вам нужно будет продолжить процесс, чтобы получить желаемый результат.

Если вы обновитесь до MySQL 8, вы получите CTE, но все равно не получите БОЛЬШИХ запросов.

Редактировать: Я пошел еще дальше, чтобы определить дубликаты имен. Без CTE этот запрос выглядит все более уродливым:

select z.*, y.times
  from (
    select name, trim(replace(lower(name), lower('Dr.'), '')) as plain_name
      from my_table
  ) z,
  (
    select plain_name, count(*) as times
      from (
        select name, trim(replace(lower(name), lower('Dr.'), '')) as plain_name
          from my_table
      ) x
      group by plain_name
      having count(*) > 1
  ) y
  where z.plain_name = y.plain_name;
...