La emocionante escena de mi operación de MySQL

Estoy participando en el "Programa de Vela · Nuggets"

antecedentes

Hace unos días, por necesidades laborales, el líder del equipo me organizó una tarea de limpieza de datos.

Tarea: Pasar los datos de la tabla A a la tabla B.

Mi primera reacción, ¿qué es "lavar"? ¿Qué es el lavado de datos? Sé sobre el lavado de dinero.

Pero no puedo entrar en pánico, así que le pregunté al líder del equipo.

Yo: Líder del equipo, ¿qué significa lavar los datos de la tabla A a la tabla B?

El líder del equipo parecía impotente, se cubrió la cara con las manos, odiaba que el hierro no fuera acero y luego lo ajustó, aún así me dijo con paciencia, lo que probablemente significa que ahora necesitamos los datos de la tabla A en la tabla B, los campos en tabla A y tabla B El significado es el mismo, pero el valor puede ser diferente, lo que requiere que procesemos, en el proceso de pasar los datos de la tabla A a la tabla B, hacer que los datos sean correctos.

Basado en mi comprensión limitada, no entendí muy bien los llamados "datos de lavado" en ese momento, y los campos de la tabla A no coincidían con los campos de la tabla B. Los campos de A obviamente eran más que los campos de B, y algunos campos también fueron nombrados. Es diferente de B, pero la expresión es la misma, ¿cómo lavarlo?

¡Busqué tan frenéticamente cómo lavar los datos!

Daré un ejemplo aquí para dar respectivamente la tabla A y la tabla B. Por supuesto, solo enumero una parte de los campos, y ahora asumo que solo hay una cantidad limitada de campos.

Tabla A

Los campos de una tabla:name, province_id, city_id, area_id, tech_id, crop_id, field_id, create_time, update_time, xxx, yyy, zzz, ...

Hay más campos en la tabla A que en la tabla B. Necesito lavar los datos de la tabla A en la tabla B, y solo procesar los campos que necesito e ignorar los innecesarios.

Hay más de 20.000 registros en la tabla A y hay más de 200 registros en la tabla B que inserté yo mismo.

Por supuesto, después de proporcionar la tabla A, también se proporciona un modelo de entidad (JavaBean, Entity, muchos nombres, campanas y silbatos)

public class A {
    private String name;
    private Long provinceId;
    private Long cityId;
    private Long areaId;
    private Long techId;
    private Long cropId;
    private Date createTime;
    private Date updateTime;
    ...
}
复制代码

Formulario B

Campos de la tabla B:name, province_id, city_id, area_id, mature_id, crop_id, create_time, update_time

restaurar la escena

A continuación simulo las dos tablas de la base de datos en el entorno de prueba, la anterior es la tabla A (más de 20.000 registros, aquí solo simulé 7), y la siguiente tabla B (más de 200 registros).

Ideas de lavado de datos

En primer lugar, primero descubro los campos en la tabla A que pueden coincidir con el significado de la tabla B y luego inserto todos los datos de la tabla A en la tabla B.

Entonces, encontré los siguientes campos:

name, province_id, city_id, area_id, tech_id, crop_id, update_time

Después de eso, los datos recién insertados se procesan en la tabla B, es decir, los datos se lavan .

写 SQL 操作

主要的 SQL 语句是:

INSERT INTO 目标表(字段1, 字段2, ...) SELECT 字段1, 字段2, ... FROM 来源表 WHERE 条件;
复制代码

于是,便这样操作:

INSERT INTO b(name, province_id, city_id, area_id, mature_id, crop_id, update_time) 
SELECT name, province_id, city_id, area_id, tech_id, crop_id, update_time FROM a;
复制代码

操作是正常的,成功将 A 中 2 万多条记录全部插入到了 B 中。

但是!我漏了一个字段,就是 create_time

于是,想着对这个字段进行更新,将 A 中这个字段更新到 B 中。

于是写了一条SQL语句。

UPDATE b(create_time) SET create_time = (SELECT create_time FROM a);
​
> 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(create_time) SET create_time = (SELECT create_time FROM a)' at line 1
复制代码

噢,看来不能这样更新啊!(一个大嘴巴子过去,写错了还没发现)

换种写法:

UPDATE b AS tb, (SELECT create_time FROM a) AS ta SET tb.create_time = ta.create_time;
复制代码

可以,噩梦开始了!

更新了非常久,看着十几秒的SQL执行到六七百秒还没执行完,心里着实很慌!眼看着数据库可能会崩,我不得不向我的组长求救了!

这时问题出现了,有人数据库连接不上了,可见这严重性,已经影响到其他人的使用了!

噩梦

于是我组长来帮我处理了,想着 kill 掉我的 navicat ,但是 kill 掉还是没效果,毕竟这个 SQL 已经在执行了。

我:能不能重启这个 MySQL 服务?

组长一波连环炮过来了

组长:重启?你知道这个 MySQL 有多少人在用吗?又不只是我们在用,你重启其他人怎么搞?

我哑口无言,心里非常忐忑,想着闯祸了,GG,就看着他操作。没过多久,经过他的一顿操作,终于解决了这个问题。我的心里的一块悬着的大石终于放下了,还好解决了。组长牛逼,救世主!

我:如何解决的?

组长:将这个事务回滚解决的,你更新的 SQL 怎么写的?(努力回想)

于是写出了上面写的 SQL:

UPDATE b AS tb, (SELECT create_time FROM a) AS ta SET tb.create_time = ta.create_time;
复制代码

组长:你为什么这样写?不应该把子查询写在 SET tb.create_time 后面吗?

我:对啊,我一开始就是把这个子查询写在它后面的,但是提示我语法错误,我就换了一种写法。

组长:那你写写你说提示错误的 SQL。

于是我又丢出来一个 SQL:

UPDATE b SET create_time = (SELECT create_time FROM a);
复制代码

实际上,这条 SQL 也是不行的,子查询返回的结果不止一行,而当前 SET 是更新某一行的。

正确的写法是:

UPDATE b AS tb 
SET create_time = (SELECT create_time FROM a AS ta WHERE tb.id = ta.id AND tb.name = ta.name)
复制代码

成功更新B表

博客园-SQL把一个表中数据更新到另一个表的多种方法

最后组长深思,你 B 表已经有 2 万多条记录了,A 表也有 2 万多条记录,你这样更新,每一次都需要子查询查出 A 表的 2 万多条记录,B 也有 2 万多条记录,这样成笛卡尔积了,你知道什么是笛卡尔积吧?2 万 × 2 万 = 4 亿的记录行了,难怪这么久。

让我重新操作,那么现在我会在原先的SQL加上WHERE条件,这样写:

UPDATE b AS tb, (SELECT create_time, name FROM a) AS ta 
SET tb.create_time = ta.create_time
WHERE tb.id = ta.id AND tb.name = ta.name;
复制代码

总结

情况:漏了某一个字段 X,需要将 A 表的这个字段列值更新到 B 表

条件:A 中的 id 字段的值等于 B表中的 id 字段的值 且 A 中的 name 字段的值等于 B 中 name 字段的值(条件为什么这样写?)。

条件这样写主要是因为 表和表之间的关联关系 可能有多个字段,此处只选二个字段,多个依此类推。

操作:

  • 一张表的数据插入到另一张表,可以这样写:
INSERT INTO 目标表(字段1, 字段2, ...) SELECT 字段1, 字段2, ... FROM 来源表 WHERE 条件;
复制代码
  • 批量更新一张表的某个字段到另一张表,那么 SQL 可以类似这样写:
# 写法一
UPDATE b AS tb 
SET create_time = (SELECT create_time FROM a AS ta WHERE tb.id = ta.id AND tb.name = ta.name)

# 写法二
UPDATE b AS tb, (SELECT create_time, name FROM a) AS ta 
SET tb.create_time = ta.create_time
WHERE tb.id = ta.id AND tb.name = ta.name;
复制代码

所谓洗数据:在我的理解中,就是把旧数据,按照新数据的规则把旧数据不正确的值修改正确,同时把这些旧数据插入到新数据中,成为新数据。举个例子,A 表中的 province_id,值为 10 代表 广东,而 B 表中的 province_id ,值为 19 代表 广东,把 A 表中的数据插入到 B 表的过程中,把值为 10 修改为 19,这样插入的数据才能在 B 表中正确表示 广东,这个过程就是「洗数据」,当然,也可以在插入后再修改,不管过程是怎样,最终能把数据的值修改正确,就是洗数据!

教训:

  1. 数据量大的表,少在测试环境操作,要操作尽量保证写的 SQL 是正确的,能在本地环境操作就现在本地环境操作!
  1. 能用 Java 代码进行操作,优先写 Java 代码操作!

最后的最后

由本人水平所限,难免有错误以及不足之处, 屏幕前的靓仔靓女们 如有发现,恳请指出!

最后,谢谢你看到这里,谢谢你认真对待我的努力,希望这篇博客对你有所帮助!

你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!

Supongo que te gusta

Origin juejin.im/post/7150156765600940039
Recomendado
Clasificación