本文主要講述如何在 awk 中實現 SQL 的常用操作,當做個簡單的 awk 入門分享。
雖然文中部分 awk 會有其它更簡潔高效的 shell 命令去完成,亦或是其它語言去完成,
但這都不在本文的討論範疇。
注:本文所用到的兩個測試文件 user、consumer,分別模擬兩張 SQL 表:
user 表,字段:
id name addr
1 zhangsan hubei
3 lisi tianjin
4 wangmazi guangzhou
2 wangwu beijing
consumer 表,字段:
id cost date
1 15 20121213
2 20 20121213
3 100 20121213
4 99 20121213
1 25 20121114
2 108 20121114
3 100 20121114
4 66 20121114
1 15 20121213
1 115 20121114
測試環境:
OS 版本:
uname -a
CYGWIN_NT-6.1 june-PC 1.7.9(0.237/5/3) 2011-03-29 10:10 i686 Cygwin
awk 版本:
awk --version
GNU Awk 3.1.8
1、查詢整張表記錄,where 條件過濾,關鍵詞:where
select * from user;
awk 1 user;
select * from consumer where cost > 100;
awk '$2>100' consumer
2、對某個字段去重,或者按記錄去重,關鍵詞:distinct
select distinct(date) from consumer;
awk '!a[$3]++{print $3}' consumer
select distinct(*) from consumer;
awk '!a[$0]++' consumer
3、記錄按序輸出,關鍵詞:order by
select id from user order by id;
awk '{a[$1]}END{asorti(a);for(i=1;i<=length(a);i++){print a[i]}}' user
4、取前多少條記錄,關鍵詞:limit
select * from consumer limit 2;
awk 'NR<=2' consumer
awk 'NR>2{exit}1' consumer # performance is better
5、分組求和統計,關鍵詞:group by、having、sum、count
select id, count(1), sum(cost) from consumer group by id having count(1) > 2;
awk '{a[$1]=a[$1]==""?$2:a[$1]","$2}END{for(i in a){c=split(a[i],b,",");if(c>2){sum=0;for(j in b){sum+=b[j]};print i"\t"c"\t"sum}}}' consumer
6、模糊查詢,關鍵詞:like(like屬於通配,也可正則 REGEXP)
select name from user where name like 'wang%';
awk '$2 ~/^wang/{print $2}' user
select addr from user where addr like '%bei';
awk '/.*bei$/{print $3}' user
select addr from user where addr like '%bei%';
awk '$3 ~/bei/{print $3}' user
7、多表 join 關聯查詢,關鍵詞:join
select a.* , b.* from user a inner join consumer b on a.id = b.id and b.id = 2;
awk 'ARGIND==1{a[$1]=$0;next}{if(($1 in a)&&$1==2){print a[$1]"\t"$2"\t"$3}}' user consumer
8、多表水平聯接,關鍵詞:union all
select a.* from user a union all select b.* from user b;
awk 1 user user
select a.* from user a union select b.* from user b;
awk '!a[$0]++' user user
9、隨機抽樣統計,關鍵詞:order by rand()
SELECT * FROM consumer ORDER BY RAND() LIMIT 2;
awk 'BEGIN{srand();while(i<2){k=int(rand()*10)+1;if(!(k in a)){a[k];i++}}}(NR in a)' consum
10、篩選文件中出現過多次的字符
awk -F',' '{a[$4]++}END{for( key in a){if(a[key]>1){print key"\t"a[key]}} }' test_4.csv
11、行列轉換,關鍵詞:SUM(IF())、WITH ROLLUP
MySQL 寫法:http://my.oschina.NET/leejun2005/blog/77796
awk 寫法:http://hi.baidu.com/leejun_2005/item/2bac30c2b97e5e56ad00ef86
awk 小應用之 RTX 訂餐統計:
1、功能:
統計 rtx 聊天記錄中的訂餐信息,包括且限於:菜名、人員姓名、人數
2、支持的功能:
訂餐、取消、修改
3、格式:
訂餐:“+1 空格 菜名”,如: “+1 雞腿” // 不含雙引號
取消:“-1” 即可, 如: “-1” // 不含雙引號
修改:格式同訂餐一樣,會自動根據姓名覆蓋
4、使用限制與注意事項:
(1)必須嚴格遵守格式,否則會統計錯誤,例如:菜名和+1-1之間要空格分隔,且必須 -1+1 開頭
(2)如果一人代訂多人,需要複製格式,修改姓名,然後發佈多條信息,
格式:
//代訂 // 這一行一定要帶上,不能以 +-( 字符開頭
(userName) //要以 ( 打頭,如果你自己點多份,請在名字後面帶上數字序號,如 userName1
+1 菜名
暫不支持直接 “+2 菜名” 這種形式,因爲最後需要按姓名彙總
(3)此 awk 腳本需要在 4.0 版本以上運行,因爲 4.0 以下的 HashMap 不支持中文 key。
測試用例:
echo "
user(統計測試) 18:30:52
對吧
user(統計測試) 18:30:55
下單了,嗯
user(張三) 18:31:11
+1 西瓜泡方便麪
user(統計測試) 18:30:52
對吧 -1 測試
user(統計測試) 18:30:52
// 這是幫人代訂的測試,這行一定要,隨便寫點啥都行 -------------------- 測試代訂功能
(代訂測試人)
+1 豆腐腦-甜的
。。。。。。。。。
(代訂測試人2)
+1 豆腐腦-酸的
user(統計測試) 18:30:55
下單了,嗯
user(李四) 18:31:11
+1 大排
user(李四) 18:31:11
-1
user(統計測試) 18:30:52
對吧
user(統計測試) 18:30:55
下單了,嗯
user(張三) 18:31:11
+1 帶魚
user(王麻子) 18:31:11
+1 大蒜
user(統計測試) 18:30:55
下單了,嗯
user(測試程序) 18:31:11
+1 唐僧肉
user(測試程序1) 18:31:11
+1 帶魚
user(趙六) 18:31:11
+1 大蒜
"|\
awk '//{gsub(/.*\(|.*/,"");name=$0;getline;if(!($0~/^(\+|-)/))next;a[name]=$0}END{for(i
in a){split(a[i],b," ");if(b[2]=="")continue;c[b[2]]=c[b[2]]==""?i:c[b[2]]","i};for(i in c){split(c[i],d,",");print i":\t"c[i]"\t"length(d)}}'|column -t
結果:
帶魚: 測試程序1,張三 2
唐僧肉: 測試程序 1
大蒜: 趙六,王麻子 2
豆腐腦-酸的: 代訂測試人2 1
豆腐腦-甜的: 代訂測試人 1
12、查找父ID
echo "1 0
11 1
111 11
1111 111"|awk '{a[$1]=$2;if($2==0){b[$1]=$12}}END{for(i in a){j=i;c=0;while(a[j]!=0){j=a[j];c++};print i"\t"j"\t"c}}'
結果:
id rootId level
1111 1 3
111 1 2
11 1 1
1 1 0
關於 id 間父子關係的建立與查找,還可以參考這個例子中的 Python 寫法:
python 數據結構轉換,將線性元祖轉換成字典樹:
http://segmentfault.com/q/1010000000415526
t = (
(1, -1, 'python'),
(2, -1, 'ruby'),
(3, -1, 'php'),
(4, -1, 'lisp'),
(5, 1, 'flask'),
(6, 1, 'django'),
(7, 1, 'webpy'),
(8, 2, 'rails'),
(9, 3, 'zend'),
(10, 6, 'dblog')
)
# fid 無序版
from itertools import groupby
from operator import itemgetter as get
from pprint import pprint
# group by fid
tmp = dict([(k, list(rows)) for k, rows in groupby(sorted(t, key=get(1)), get(1))])
def map_fun(row):
item = dict(zip(('id', 'fid', 'title'), row))
if row[0] in tmp:
item['son'] = find_children(row[0])
return item;
def find_children(parent):
return map(map_fun, tmp[parent])
pprint(find_children(-1))
t = (
(1, -1, 'python'),
(2, -1, 'ruby'),
(3, -1, 'php'),
(4, -1, 'lisp'),
(5, 1, 'flask'),
(6, 1, 'django'),
(7, 1, 'webpy'),
(8, 2, 'rails'),
(9, 3, 'zend'),
(10, 6, 'dblog')
)
# fid 有序版
from pprint import pprint
l = []
entries = {}
for id, fid, title in t:
entries[id] = entry = {'id': id, 'fid': fid, 'title': title}
if fid == -1:
l.append(entry)
else:
parent = entries[fid]
parent.setdefault('son', []).append(entry)
pprint(l)
【updating】 本文將會不定期更新。。。