【问题标题】:Mysql: Concatenate Duplicate Data but ignore string in duplicatesMysql:连接重复数据但忽略重复的字符串
【发布时间】:2018-09-10 19:05:24
【问题描述】:

有没有办法在忽略给定字符串的同时查找重复数据?

例如,如果我有一个名称表,有没有办法连接名称为“Ann Smith”但忽略字符串“Dr.”的行。例如,包含“Ann Smith”和“Dr. Ann Smith”的行应该连接成一个名为“Dr. Ann Smith”的行。如果名称匹配(减去“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

【问题讨论】:

  • 编辑您的问题并以表格格式提供示例数据和所需结果。
  • 很抱歉。
  • 这不是真正的串联,这是关于模糊匹配,这不是那么容易做到的。
  • 如果“给定字符串”是静态值并且是“博士”,可能与此类似:select name from t group by replace(name, 'Dr. ', '') ?
  • MySQL 8 还是 MySQL 5.x?

标签: mysql sql mysql-5.7 fuzzy-comparison


【解决方案1】:

要执行您想要的操作,您可能需要 CTE(通用表表达式)和 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,但仍不会获得 LATERAL 查询。

编辑:我进一步识别了重复的名称。如果没有 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;

【讨论】:

  • 我收到关于 group by 中没有 x.name 的错误。我应该将它添加到 group by 语句中吗?
  • 已修复。我添加了一个额外的处理步骤来帮助识别重复的行。
【解决方案2】:

假设这些是完全嵌套的,您可以通过以下方式获得“长格式”:

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;

【讨论】:

    【解决方案3】:

    我最终使用了上述答案的组合。首先,我创建了一个临时表来修剪和替换 'Dr. ' 带有空字符串的字符串。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-12
      • 2015-06-11
      • 1970-01-01
      • 2013-02-27
      • 1970-01-01
      • 2017-10-25
      • 1970-01-01
      • 2013-11-30
      相关资源
      最近更新 更多