MySQL:从另一个表中的值“修补”表上的现有数据

Posted

技术标签:

【中文标题】MySQL:从另一个表中的值“修补”表上的现有数据【英文标题】:MySQL: "Patch" existing data on a table from values in another table 【发布时间】:2021-03-22 22:01:30 【问题描述】:

我有两张表,结构相同。第一个填充有从另一个系统获得的可能需要更正的记录(可能是一个或多个列)。第二个表是我想应用于第一个表的更正。

例如,我可以在 table1 上有以下行:

order_number | name         | email        | tracking_no
101            null           foo@bar.com    3456789
102            An Example     ex@ample.com   1010101

...以及我想对 table2 上的这些行应用的更正:

order_number | name         | email        | tracking_no
101            Name Surname   null           null
102            null           null           45778901

本质上:将缺少的name 添加到order_number 101 并更正错误的tracking_noorder_number 102。

我正在尝试做的逻辑是:table1 中的“补丁”值与 table2 中相同的 order_number 包含的更正,优先于 table2 中的值,如果相应的不覆盖 table1 中的现有值table2 中的值为空。

对于 table1 中的值为 null 并且我们在 table2 中进行非 null 更正的情况,COALESCE 似乎是正确的方法,但我不知道如何用表 2 中相应的“修复”。

mysql/MariaDB 中是否有一种机制可以让我这样做,因为替代方案是一个非常混乱的“从两个表中提取两条记录,比较值并建立新的正确记录并将其插入回 table1”。

正如 cmets 中所指出的,这里有一组可重现的测试数据以及表结构:

USE so_demo;

DROP TABLE IF EXISTS so_demo.table1;
DROP TABLE IF EXISTS so_demo.table2;

CREATE TABLE so_demo.table1 (
  order_number int(11) NOT NULL AUTO_INCREMENT,
  name varchar(50) DEFAULT NULL,
  email varchar(250) DEFAULT NULL,
  tracking_no varchar(255) DEFAULT NULL,
  PRIMARY KEY (order_number),
  UNIQUE INDEX UK_table1_order_number (order_number)
)
ENGINE = INNODB,
CHARACTER SET utf8mb4,
COLLATE utf8mb4_general_ci;

CREATE TABLE so_demo.table2 (
  order_number int(11) NOT NULL AUTO_INCREMENT,
  name varchar(50) DEFAULT NULL,
  email varchar(250) DEFAULT NULL,
  tracking_no varchar(255) DEFAULT NULL,
  PRIMARY KEY (order_number),
  UNIQUE INDEX UK_table2_order_number (order_number)
)
ENGINE = INNODB,
CHARACTER SET utf8mb4,
COLLATE utf8mb4_general_ci;

INSERT INTO so_demo.table1 VALUES (101, NULL, "foo@bar.com", 3456789);
INSERT INTO so_demo.table1 VALUES (102, "An Example", "ex@ample.com", 1010101);

INSERT INTO so_demo.table2 VALUES (101, "Name Surname", NULL, NULL);
INSERT INTO so_demo.table2 VALUES (102, NULL, NULL, 45778901);

【问题讨论】:

你的表1上是否有索引 @P.Salmon 是的,order_number 是唯一索引。 见:Why should I provide an MCRE for what seems to me to be a very simple SQL query? @Strawberry 很公平,在问题上添加了结构和测试数据 您能否编辑以显示更新后所需的实际结果 【参考方案1】:

您要查找的术语是合并,在 mysql 中插入重复键

drop table if exists t,t1;

create table t(order_number int primary key, name  varchar(20)       , email  varchar(20), tracking_no int);
insert into t values
(101       ,     null       ,     'foo@bar.com'  ,  3456789),
(102       ,     'An Example',     'ex@ample.com' ,  1010101);

create table t1(order_number int, name  varchar(20), email  varchar(20), tracking_no int);
insert into t1 values
(101       ,     'Name Surname', null   ,        null),
(102       ,     null          , null   ,        '45778901');


insert into t
select * from t1
on duplicate key update
    t.name = case when t1.name is not null then t1.name else t.name end,
    t.email = case when t1.email is not null then t1.email else t.email end,
    t.tracking_no = case when t1.tracking_no is not null then t1.tracking_no else t.tracking_no end
;

select * from t;

+--------------+--------------+--------------+-------------+
| order_number | name         | email        | tracking_no |
+--------------+--------------+--------------+-------------+
|          101 | Name Surname | foo@bar.com  |     3456789 |
|          102 | An Example   | ex@ample.com |    45778901 |
+--------------+--------------+--------------+-------------+
2 rows in set (0.001 sec)

【讨论】:

t.name=Coalesce(t1.name, t.name) :) 这就是我想要实现的目标,谢谢@P.Salmon!进一步的查询:我不介意只复制 case 语句,但我正在处理的实际表有大约 50 列。是否有将相同的 case 语句应用于所有列的简写?谢谢。 恐怕不会 - 尽管正如已经指出的那样,coalesce 不那么冗长。

以上是关于MySQL:从另一个表中的值“修补”表上的现有数据的主要内容,如果未能解决你的问题,请参考以下文章

从另一个表中逐行计数,在sql中的两个表上保存一些条件

从另一个表上的 Where 表中选择计数

将表上的现有条目转换为Hibernate实体对象

用于向表中添加新行的存储过程,它检查值以验证它们在外部表上的值

Mysql在同一张表上的多个左连接

仅更改活动工作表上的值