如何使用另一个表中的匹配值替换/更新列中每个字符串的所有实例?

时间:2015-06-15 18:35:43

标签: mysql sql

将数据存储在逗号分隔的字符串中并不取决于我,这不是我可以在我的数据库中更改的内容所以请耐心等待。我已经在网上和stackoverflow上进行了相当多的搜索,但如果甚至可以使用MySQL,我找不到解决方案。

我试图用table2中的匹配值替换table1中每个唯一字符串的所有实例。我尝试过通配符,替换,更新,加入等等,我只是不确定如何使它工作。我知道每个字符串的一个解决方案是replace(),但table2有超过200行,这意味着嵌套超过200次。

这就是我想要完成的事情。我有两个表,table1:

+------+-------------+
| Item | Code        |
+------+-------------+
| 1    | 614         |
+------+-------------+
| 2    | 212,614,415 |
+------+-------------+
| 3    | 212,303     |
+------+-------------+
| ...  | ...         |
+------+-------------+

和table2:

+------+-------------------+
| Code | Name              |
+------+-------------------+
| 614  | Columbus, OH      |
+------+-------------------+
| 212  | New York, NY      |
+------+-------------------+
| 415  | San Francisco, CA |
+------+-------------------+
| 303  | Ft. Worth, TX     |
+------+-------------------+
| ...  | ...               |
+------+-------------------+

我想用table2中的相应值替换table1中的代码以产生此结果:

+------+---------------------------------------------+
| Item | Code                                        |
+------+---------------------------------------------+
| 1    | Columbus, OH                                |
+------+---------------------------------------------+
| 2    | New York, NY,Columbus, OH,San Francisco, CA |
+------+---------------------------------------------+
| 3    | New York, NY,Ft. Worth, TX                  |
+------+---------------------------------------------+
| ...  | ...                                         |
+------+---------------------------------------------+

2 个答案:

答案 0 :(得分:1)

这应该这样做(参见下面的最后一个查询)。我在联接中包含了逗号,因此12和12之类的id与你所拥有的id和212的id不匹配(例如)。

drop table if exists table1;

drop table if exists table2;

create table table1(
    item int,
    code varchar(64)
);

create table table2(
    code int,
    name varchar(64)
);

insert into table1 values (1, '614');
insert into table1 values (2, '212,614,415');
insert into table1 values (3, '212,303');

insert into table2 values(212, 'New York, NY');
insert into table2 values(303, 'Ft. Worth, TX');
insert into table2 values(415, 'San Francisco, CA');
insert into table2 values(614, 'Columbus, OH');

select * from table1

+ --------- + --------- +
| item      | code      |
+ --------- + --------- +
| 1         | 614       |
| 2         | 212,614,415 |
| 3         | 212,303   |
+ --------- + --------- +
3 rows

select * from table2

+ --------- + --------- +
| code      | name      |
+ --------- + --------- +
| 212       | New York, NY |
| 303       | Ft. Worth, TX |
| 415       | San Francisco, CA |
| 614       | Columbus, OH |
+ --------- + --------- +
4 rows

select 
    t1.item,
    t2.name
from
    table1 t1 join table2 t2 on (
        t1.code = t2.code
        or t1.code like concat(t2.code, ',%')
        or t1.code like concat('%,', t2.code, ',%')
        or t1.code like concat('%,', t2.code)
    )
order by t1.item

+ --------- + --------- +
| item      | name      |
+ --------- + --------- +
| 1         | Columbus, OH |
| 2         | Columbus, OH |
| 2         | New York, NY |
| 2         | San Francisco, CA |
| 3         | Ft. Worth, TX |
| 3         | New York, NY |
+ --------- + --------- +
6 rows

编辑: 或者如果你想保持数据非规范化,如下所示:

select 
    t1.item,
    group_concat(t2.name)
from
    table1 t1 join table2 t2 on (
        t1.code = t2.code
        or t1.code like concat(t2.code, ',%')
        or t1.code like concat('%,', t2.code, ',%')
        or t1.code like concat('%,', t2.code)
    )
group by t1.item
order by t1.item

+ --------- + -------------------------- +
| item      | group_concat(t2.name)      |
+ --------- + -------------------------- +
| 1         | Columbus, OH               |
| 2         | Columbus, OH,New York, NY,San Francisco, CA |
| 3         | Ft. Worth, TX,New York, NY |
+ --------- + -------------------------- +
3 rows

答案 1 :(得分:0)

在这里,我们看到一个完美的例子,说明为什么在数据库字段中使用逗号分隔列表是一个坏主意。它们比合适的关系表更难操纵。

考虑到这一点,我会考虑首先将代码拆分为多个记录,然后执行基于简单集的替换,然后将它们重新组合在一起。基本上:

  1. 使用split function创建临时表tmp1,每个项目/代码对都有1条记录。

  2. 然后从tmp1加入到table1的tmp1.code上执行UPDATE。

  3. 最后使用GROUP_CONCAT将名称重新组合在一起。