关于 awk 用于 sql 脚本拼写的数据去重处理
由于数据库表设计初期考虑欠佳,经常出现数据重复的情况.因此需要删除其中的重复数据,然后对数据库表添加唯一索引从而从表设计上避免重复数据产生.这里举例的场景纯属虚构.主要是为了说明 awk 的这一使用方法.
数据
考虑如下数据
数据 ID | 用户名(userName) | 订单号 (orderNo) | 评论 (comment) |
---|---|---|---|
1 | 张三 | 10100001 | 途家民宿体验不错 |
2 | 李四 | 10100002 | 第一次住途家民宿 |
3 | 李四 | 10100003 | 第二次入住途家民宿,体验还是一如既往的好! |
4 | 李四 | 10100003 | 第二次入住途家民宿,体验还是一如既往的好! |
5 | 乔峰 | 10100008 | 这次来中原,第一次体验途家民宿,非常适合江湖人士! |
6 | 乔峰 | 10100008 | 这次来中原,第一次体验途家民宿,非常适合江湖人士! |
如下,假设一个订单一个入住人只能评论一次, 这里由于设计缺陷,导致数据重复;这里需要把重复数据筛选出来.并生成相应的删除 SQL.
假设有重复的数据已经生成,并放到了一个 txt 文件中.第一反应可以使用 sort
和 uniq
等相应的命令来完成此去重.但是实际使用场景都不太匹配.
awk
命令的命令模型(参考:shell-awk)为 模式 + {行为(Action)}
awk的程序指令由模式和操作组成,即Pattern { Action }的形式,如果省略Action,则默认执行 print $0 的操作.
因此,借助此特性,只要能够识别一行数据在流式处理时,前面是否已经出现过.就可以决定是打印此行,还是不打印此行;
实现去除重复功能的就是这里的Pattern:bash!a[$0]++
; 在awk中,对于未初始化的数组变量,在进行数值运算的时候,会赋予初值0,因此a[$0]=0,++运算符的特性是先取值,后加1,因此Pattern等价于:!0
,这个 Pattern 的意思就是如果$0
没有出现过,就打印此行的值(没有写 Action 的时候默认是打印整行!);
针对此场景: 需要反过来,第一次出现的略过,不进行处理.第二次以上出现的需要输出一行删除此数据的 sql; 这里进行两个小改动:
- 把
$0
修改为需要判定唯一性的字符串,这里需要进行字符串拼接:$3"-"$4
,用这个联合唯一索引进行去重.然后再重写action部分:
处理过程
源数据:
| 1 | 张三 | 10100001 | [途家](http://www.tujia.com)民宿体验不错 |
| 2 | 李四 | 10100002 | 第一次住途家民宿 |
| 3 | 李四 | 10100003 |第二次入住途家民宿,体验还是一如既往的好! |
| 4 | 李四 | 10100003 |第二次入住途家民宿,体验还是一如既往的好! |
| 5 | 乔峰 | 10100008 |这次来中原,第一次体验途家民宿,非常适合江湖人士! |
| 6 | 乔峰 | 10100008 |这次来中原,第一次体验途家民宿,非常适合江湖人士! |
脚本:
[macbook@localhost ~/Desktop]$cat test.txt | awk -F"|" 'a[$3"-"$4]++'
| 4 | 李四 | 10100003 |第二次入住途家民宿,体验还是一如既往的好! |
| 6 | 乔峰 | 10100008 |这次来中原,第一次体验途家民宿,非常适合江湖人士! |
拼 SQL:
[macbook@localhost ~/Desktop]$cat test.txt | awk -F"|" 'a[$3"-"$4]++ {print "delete from xxx where id ="$2";"}'
delete from xxx where id = 4 ;
delete from xxx where id = 6 ;
本文处理参考了如下文章:
[1] Linux命令去重统计排序
[2] awk 中各种模式详解