awk實現數據庫查詢功能

本文主要講述如何在 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'),
    (51'flask'),
    (61'django'),
    (71'webpy'),
    (82'rails'),
    (93'zend'),
    (106'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[0in 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'),
    (51'flask'),
    (61'django'),
    (71'webpy'),
    (82'rails'),
    (93'zend'),
    (106'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】 本文將會不定期更新。。。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章