mysql不小心删除数据解决方案

参考文章简要的1
https://blog.51cto.com/402753795/1826074
参考文章细节的2
https://blog.csdn.net/weixin_43733154/article/details/104639335
参考文章细节的3
https://blog.csdn.net/weixin_33674976/article/details/92863378
python脚本
b.py

#_*_ coding:utf-8 _*_
import sys
import os
import io

binlogfile = sys.argv[1]
database_name = sys.argv[2]
table_name = sys.argv[3]
print('--database="'+database_name+'"')
def format_binlog():
    os.system('/www/server/mysql/bin/mysqlbinlog --start-datetime="2021-11-25 08:20:45" --stop-datetime="2021-11-25 16:50:00"  -v -v  --base64-output=DECODE-ROWS  /www/server/mysql/bin/'+binlogfile+' > '+binlogfile+'.txt')

def pickupbinlog():
    f = io.open(binlogfile+'.txt','r')
    fw = io.open(database_name+'_'+table_name+'_'+binlogfile+'.txt','a')
    priv_str = ''
    priv_line = ''
    goal_flag = 0
    for row in f:
        # 处理首行
        if row[0:3] == '###' and priv_str != '###':
            if database_name in row and table_name in row:
                goal_flag = 1
                fw.write(priv_line)
                fw.write(row)
        # 处理末行
        if row[0:3] != '###' and priv_str == '###':
            goal_flag = 0
        # 处理目标操作
        if row[0:3] == '###' and priv_str == '###' and goal_flag == 1:
            fw.write(row)
        priv_str = row[0:3]
        priv_line = row
    f.close()
    fw.close()

if __name__ == '__main__':
    # python2.7 pickupbinlog.py mysql-bin.001051 dbname tablename
    # python3 pickupbinlog.py mysql-bin.001051 dbname tablename
    format_binlog()
    pickupbinlog()

执行命令 python b.py binlog文件名 数据库名 数据表名
假设binlog文件名:mysql-bin.000471
假设数据库名:beiyaozhongtai
数据表名:zt_product_base
执行命令如下:

python b.py mysql-bin.000471 beiyaozhongtai zt_product_base

非删除语句系统会生成sql数据如下:格式

# at 1569
#160713 13:52:06 server id 1  end_log_pos 1569   Table_map: `students`.`test` mapped to number 33
#160713 13:52:06 server id 1  end_log_pos 1789   Update_rows: table id 33 flags: STMT_END_F
### UPDATE `students`.`test`
### WHERE
###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
###   @2='张三' /* STRING(60) meta=65084 nullable=0 is_null=0 */
###   @3='男' /* STRING(12) meta=65036 nullable=0 is_null=0 */
###   @4='86' /* VARSTRING(30) meta=30 nullable=0 is_null=0 */
### SET
###   @1=1 /* INT meta=0 nullable=0 is_null=0 */
###   @2='张三' /* STRING(60) meta=65084 nullable=0 is_null=0 */
###   @3='中' /* STRING(12) meta=65036 nullable=0 is_null=0 */
###   @4='86' /* VARSTRING(30) meta=30 nullable=0 is_null=0 */
### UPDATE `students`.`test`
### WHERE
###   @1=2 /* INT meta=0 nullable=0 is_null=0 */
###   @2='李四' /* STRING(60) meta=65084 nullable=0 is_null=0 */

删除的语句是这样的

############################## 处理 a.txt 文件,生成 b.txt 文件 #######################
[root@node21 tmp]# sed -n '/^###/'p a.txt  >b.txt
[root@node21 tmp]# cat b.txt 
### DELETE FROM `lili`.`test1`
### WHERE
###   @1=10 /* INT meta=0 nullable=0 is_null=0 */
###   @2='cl10' /* VARSTRING(60) meta=60 nullable=0 is_null=0 */
###   @3=1 /* ENUM(1 byte) meta=63233 nullable=0 is_null=0 */
###   @4=30 /* TINYINT meta=0 nullable=0 is_null=0 */
###   @5=180                  /* FLOAT meta=4 nullable=0 is_null=0 */
###   @6=65.5                 /* FLOAT meta=4 nullable=0 is_null=0 */
###   @7='四川信息10' /* VARSTRING(90) meta=90 nullable=0 is_null=0 */
###   @8='专科' /* VARSTRING(30) meta=30 nullable=0 is_null=0 */
###   @9='18382024230' /* STRING(33) meta=65057 nullable=0 is_null=0 */
###   @10='[email protected]' /* VARSTRING(90) meta=90 nullable=0 is_null=0 */
###   @11=7000                 /* FLOAT meta=4 nullable=0 is_null=0 */

先吧删除语句转换成insert语句

############################## 处理 b.txt 文件 去井号,生成 c.txt 文件 #######################
[root@node21 tmp]# sed 's/### //g' b.txt >c.txt
[root@node21 tmp]# cat c.txt 
DELETE FROM `lili`.`test1`
WHERE
  @1=10 /* INT meta=0 nullable=0 is_null=0 */
  @2='cl10' /* VARSTRING(60) meta=60 nullable=0 is_null=0 */
  @3=1 /* ENUM(1 byte) meta=63233 nullable=0 is_null=0 */
  @4=30 /* TINYINT meta=0 nullable=0 is_null=0 */
  @5=180                  /* FLOAT meta=4 nullable=0 is_null=0 */
  @6=65.5                 /* FLOAT meta=4 nullable=0 is_null=0 */
  @7='四川信息10' /* VARSTRING(90) meta=90 nullable=0 is_null=0 */
  @8='专科' /* VARSTRING(30) meta=30 nullable=0 is_null=0 */
  @9='18382024230' /* STRING(33) meta=65057 nullable=0 is_null=0 */
  @10='[email protected]' /* VARSTRING(90) meta=90 nullable=0 is_null=0 */
  @11=7000                 /* FLOAT meta=4 nullable=0 is_null=0 */

然后去掉井号 并且在参数后边加上逗号

############################## 处理 c.txt 文件,生成 d.txt 文件 #######################
[root@node21 tmp]# sed 's#/\*.*\*/#,#g' c.txt >d.txt
如果有富文本里面含注释语句容易出错可以更精细匹配
 sed 's#/\*.*\*/
###   @#,#g' c.txt >d.txt
[root@node21 tmp]# cat d.txt 
DELETE FROM `lili`.`test1`
WHERE
  @1=10 ,
  @2='cl10' ,
  @3=1 ,
  @4=30 ,
  @5=180                  ,
  @6=65.5                 ,
  @7='四川信息10' ,
  @8='专科' ,
  @9='18382024230' ,
  @10='[email protected]' ,
  @11=7000                 ,

继续处理把delete转成insert

############################## 处理 d.txt 文件,生成 e.txt 文件 #######################
[root@node21 tmp]# sed 's#DELETE FROM#INSERT INTO#g' d.txt >e.txt
[root@node21 tmp]# cat e.txt 
INSERT INTO `lili`.`test1`
WHERE
  @1=10 ,
  @2='cl10' ,
  @3=1 ,
  @4=30 ,
  @5=180                  ,
  @6=65.5                 ,
  @7='四川信息10' ,
  @8='专科' ,
  @9='18382024230' ,
  @10='[email protected]' ,
  @11=7000                 ,


############################## 处理 e.txt 文件,生成 f.txt 文件 #######################
[root@node21 tmp]# sed 's#WHERE#SELECT#g' e.txt >f.txt
[root@node21 tmp]# cat f.txt 
INSERT INTO `lili`.`test1`
SELECT
  @1=10 ,
  @2='cl10' ,
  @3=1 ,
  @4=30 ,
  @5=180                  ,
  @6=65.5                 ,
  @7='四川信息10' ,
  @8='专科' ,
  @9='18382024230' ,
  @10='[email protected]' ,
  @11=7000                 ,


############################## 处理 f.txt 文件,最后一个@结尾的逗号换成:生成 h.txt 文件 #######################
[root@node21 tmp]# sed -r 's#(@11=.*)(,)#\1;#g' f.txt >h.txt
[root@node21 tmp]# cat h.txt 
INSERT INTO `lili`.`test1`
SELECT
  @1=10 ,
  @2='cl10' ,
  @3=1 ,
  @4=30 ,
  @5=180                  ,
  @6=65.5                 ,
  @7='四川信息10' ,
  @8='专科' ,
  @9='18382024230' ,
  @10='[email protected]' ,
  @11=7000                 ;


############################## 处理 h.txt 文件,生成 aa.sql 文件 ######################
[root@node21 tmp]# sed -r 's#(@.*=)(.*)#\2#g' h.txt >>aa.sql
[root@node21 tmp]# cat aa.sql 
INSERT INTO `lili`.`test1`
SELECT
  10 ,
  'cl10' ,
  1 ,
  30 ,
  180                  ,
  65.5                 ,
  '四川信息10' ,
  '专科' ,
  '18382024230' ,
  '[email protected]' ,
  7000                 ;


############################## 在aa.sql文件后面添加commit;命令 ####################
[root@node21 tmp]# sed -i '$a commit;' aa.sql 
[root@node21 tmp]# cat aa.sql 
INSERT INTO `lili`.`test1`
SELECT
  10 ,
  'cl10' ,
  1 ,
  30 ,
  180                  ,
  65.5                 ,
  '四川信息10' ,
  '专科' ,
  '18382024230' ,
  '[email protected]' ,
  7000                 ;
commit;

面对非delete情况可以一步到位

这个sed会一步完成去井号,去@符,结尾加逗号
参数@4 【where最后一个@结尾用;】
这句是调换where 和 set位置

sed '/### WHERE/{:a;N;//### SET/!ba;s/([^\n])\n(.)\n(.*)/\3\n\2\n\1\n/}'

快捷生成以上sed 参数方法 利用mysql 命令获取

数据库名 'beiyao-zt-test'

数据表名 'zt_product_base'

set @irowa =0 ;
set @irowb =51 ;

SELECT GROUP_CONCAT(CONCAT("s/@",@irowa:=@irowa+1,'=/',COLUMN_NAME,'=/g') SEPARATOR ";") as a, GROUP_CONCAT("\n\(.*\)" SEPARATOR "") as b, GROUP_CONCAT(CONCAT("\",@irowb:=@irowb-1,'\n') SEPARATOR "") as b FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'beiyao-zt-test' AND TABLE_NAME = 'zt_product_base'

sed '/### WHERE/{:a;N;/### SET/!ba;s/\([^\n]*\)\n\(.*\)\n\(.*\)/\3\n\2\n\1/}' 源文件.txt | sed -r '/### WHERE/{:a;N;/@50/!ba;s/###   @2.*//g}' | sed 's#/\*.*\*/#,#g'| sed '/### WHERE/{:a;N;/@1/!ba;s/,/;/g};s/### //g;s#/\*.*\*/##g;s/COMMIT,//g' | sed '/^$/d' >test1

yichen修改后 加了50个字段的

sed '/WHERE/{:a;N;/SET/!ba;s/([^\n])\n(.)\n(.)/\3\n\2\n\1/}' beiyaozhongai_zt_product_base_mysql-bin.000471.txt | sed -r '/WHERE/{:a;N;/@50/!ba;s/### @2.//g}' | sed 's/### //g;s#/*.*/#,#g' | sed '/WHERE/{:a;N;/@1/!ba;s/,/;/g};s#/*.*/##g;s/COMMIT,//g' | sed '/^$/d' >d471.txt

结果如下:

UPDATE `students`.`test`
SET
  @1=1 ,
  @2='张三' ,
  @3='男' ,
  @4='86' ,
WHERE
  @1=1 ;
UPDATE `students`.`test`
SET
  @1=2 ,
  @2='李四' ,
  @3='男' ,
  @4='88' ,
WHERE
  @1=2 ;

把数据库名去掉

sed "s/\`beiyaozhongtai\`\.//g"

然后方式1 替换 指定@字段为数据表的字段
获取所有字段
数据库名'beiyao-zt-test'
表名'zt_product_base'
然后在sql 文件头部加上@1=id;@2=name。。。

   SET GLOBAL group_concat_max_len=102400;
       SET SESSION group_concat_max_len=102400; 
set @irow  =0 ;

SELECT GROUP_CONCAT(CONCAT("SET @",@irow:=@irow+1,'="',COLUMN_NAME,'"') SEPARATOR ";") FROM information_schema.COLUMNS 
WHERE TABLE_SCHEMA = 'beiyao-zt-test' AND TABLE_NAME = 'zt_product_base'

#如果报错
1> 1227 - Access denied; you need (at least one of) the SYSTEM_VARIABLES_ADMIN privilege(s) for this operation
需要root超级管理员授权
grant SYSTEM_VARIABLES_ADMIN on *.* to '被授权的mysql用户名';

得到如下结果

SET @1="id";
SET @2="upc";
SET @3="goods_no";
SET @4="product_name";
#下步把对应字段替换

执行下语句会生成cat文本批量替换语句

set @irow  =0 ;

SELECT GROUP_CONCAT(CONCAT("s/@",@irow:=@irow+1,'=/',COLUMN_NAME,'=/g') SEPARATOR ";") FROM information_schema.COLUMNS 
WHERE TABLE_SCHEMA = 'beiyao-zt-test' AND TABLE_NAME = 'zt_product_base'

s/@1=/id=/g;s/@2=/upc=/g;s/@3=/goods_no=/g;s/@4=/product_name=/g;s/@5=/common_name=/g;s/@6=/brand_name=/g;s/@7=/spec=/g;s/@8=/manufacture=/g;s/@9=/producing_area=/g;s/@10=/approval_number=/g;s/@11=/drug_type=/g;s/@12=/dosage_form=/g;s/@13=/packing_unit=/g;s/@14=/main_ingredients=/g;s/@15=/properties=/g;s/@16=/indications=/g;s/@17=/dosage=/g;s/@18=/adr=/g;s/@19=/taboo=/g;s/@20=/caution=/g;s/@21=/announcements=/g;s/@22=/drug_interations=/g;s/@23=/gravida_drug=/g;s/@24=/old_drug=/g;s/@25=/child_drug=/g;s/@26=/pharma_toxicology=/g;s/@27=/overdose=/g;s/@28=/pharmacokinetic=/g;s/@29=/license_legal_person=/g;s/@30=/indate=/g;s/@31=/storage_condition=/g;s/@32=/instruction_book=/g;s/@33=/attending_disease=/g;s/@34=/prescription_type=/g;s/@35=/thumbnails=/g;s/@36=/first_image=/g;s/@37=/images=/g;s/@38=/detail=/g;s/@39=/remark=/g;s/@40=/mid_package=/g;s/@41=/big_package=/g;s/@42=/create_time=/g;s/@43=/update_time=/g;s/@44=/side_effect=/g;s/@45=/spec_int=/g;s/@46=/scope_of_application=/g;s/@47=/pinyin_full=/g;s/@48=/pinyin=/g;s/@49=/type_name_one=/g;s/@50=/type_name_two=/g

然后在前面加上sed -i 即可 结尾用文件名

sed -i  上面的语句 xxx.sql
#把最后一个字段结尾逗号去掉
sed -i -r 's/(type_name_two.*),/\1/g' recover.sql
############################## 在recover.sql文件后面添加commit;命令 ####################
[root@node21 tmp]# sed -i '$a commit;' recover.sql

如果字段数量和数据库相对应也可以值替换@1= 改成id=

sed -i  's/@1=/id=/g' recover.sql

现在是这样

WHERE
  id=55344 ;
UPDATE `beiyaozhongtai`.`zt_product_base`
SET
  id=55345 ,
  @2='6970403270604' ,
  @3=NULL ,
  @4='盐酸金刚乙胺糖浆 (津彤)' ,

删除所有@符

sed -r 's#(@.*=)(.*)#\2#g' recover.sql >>aa.sql

现在是这样

WHERE
  id=55344 ;
UPDATE `beiyaozhongtai`.`zt_product_base`
SET
  id=55345 ,
  6970403270604' ,
  NULL ,
  '盐酸金刚乙胺糖浆 (津彤)' ,

在把数据库名去掉 把表名替换beiyaozhongtai. 需要转义符\

sed -i  's/`beiyaozhongtai`\.//g' recover.sql

或者所有@编号字段都指定数据库字段

#替换@为数据库的字段
sed -i 's/@1/id/g;s/@2/name/g;s/@3/sex/g;s/@4/score/g' recover.sql
#匹配最后一个字段结尾的逗号去掉
sed -i -r 's/(score.*),/\1/g' recover.sql

现在的内容就是数据库可以执行的sql了

UPDATE `students`.`test`
SET
  id=1 ,
  name='张三' ,
  sex='男' ,
  score='86'
WHERE
  id=1 ;
UPDATE `students`.`test`
SET
  id=2 ,
  name='李四' ,
  sex='男' ,
  score='88'
WHERE
  id=2 ;
UPDATE `students`.`test`

你可能感兴趣的:(mysql不小心删除数据解决方案)