前言
Q的表的基本操作與傳統(tǒng)數(shù)據(jù)庫的表的操作非常的相似,同時Q的表的操作還有一些傳統(tǒng)數(shù)據(jù)庫不具有的高級操作。但是可能因為KDB數(shù)據(jù)庫的特性,在參數(shù)和語句上有些區(qū)別。
第一個重要區(qū)別是Q表的行和列都是有序的。這在處理那些按照時間順序來記錄的數(shù)據(jù)時非常有用的。將數(shù)據(jù)追加到表中確保是按照順序的并保持不變,這對后續(xù)的select操作非常重要,就無需再排序。
第二個區(qū)別是Q表在物理上存儲為列的一個列表(list)集合。這意味著對列數(shù)據(jù)的操作是向量操作。此外,對于簡單列的列表,應用于列的原子,聚合和統(tǒng)一函數(shù)特別簡單和快速,因為它們會減少直接存儲器尋址。
第三個區(qū)別是q-sql提供了upsert語義。在字典上的更新是使用“,:”操作,意味著當應用鍵值對,并且鍵存在時,值會更新;否則插入該鍵值對。在表和鍵表的上下文中,upsert語句有著不同的操作,具體看下面的介紹。
在本篇中,我們將介紹q-sql的重要功能,從每個的簡單示例開始,我們可能會使用到官方的一個案例腳本sp.q(具體可以去官方下載或者私信我)。
一、 表的數(shù)據(jù)插入
我們有多種方法可以給表中插入數(shù)據(jù),有前面介紹的“,:”,insert,upsert。
1. “,:”插入
q)t:([] name:`symbol$(); iq:`int$()) /創(chuàng)建一個空表t
q)t
name iq
-------
q)t,:`name`iq!(`zhangsan; 42) /利用字典的形式插入數(shù)據(jù)
q)t
name iq
-----------
zhangsan 42
q)t,:`name`iq!(`lisi; 98.0) /當插入的數(shù)據(jù)類型不對時會報錯,98.0不是int類型
'type
q)t,:(`wangwu; 126) /快速簡單的給表t中插入數(shù)據(jù)
q)t
name iq
------------
zhangsan 42
wangwu 126
q)t,:(`wangwu; 126) /當添加相同數(shù)據(jù)時會重復添加
q)t /這時我們看到會有兩條相同的wangwu 126的數(shù)據(jù)
name iq
------------
zhangsan 42
wangwu 126
wangwu 126
q)kt:([eid:`long$()] name:`symbol$(); iq:`long$()) /創(chuàng)建一個含有主鍵的空表kt
q)kt,:(1002; `zhangsan; 98) /給含有主鍵的表中插入數(shù)據(jù)
q)kt
eid | name iq
----| -----------
1002| zhangsan 98
q)kt,:(1002; `lisi; 101) /當插入的數(shù)據(jù)中主鍵已經(jīng)有該記錄時(1002)會更新,而不是重復插入
q)kt
eid | name iq
----| --------
1002| lisi 101
q)kt,:(1001; `zhangsan; 101) /當插入的數(shù)據(jù)中隨后value值相同,但是主鍵中不存在該記錄時會添加該記錄
q)kt
eid | name iq
----| ------------
1002| lisi 101
1001| zhangsan 101
2. insert插入
Q語言中也有insert插入操作,其語法模板如下:
`Table_name insert Vaule
左邊是要插入的表名(一同要時`table_name的形式,前面介紹過這種方式叫pass by name),右邊是要插入的數(shù)據(jù)。其返回結(jié)果是一個插入的當前行號。
q)t:([] name:`zhangsan`lisi`wangwu; iq:42 98 126) /創(chuàng)建一個表t
q)t
name iq
------------
zhangsan 42
lisi 98
wangwu 126
q)`t insert (`name`iq)!(`wanger; 134) /使用字典的形式插入數(shù)據(jù)
,3 /返回的結(jié)果是當前插入的行號
q)t
name iq
------------
zhangsan 42
lisi 98
wangwu 126
wanger 134
q)`t insert (`sunwukong; 150) /使用普通列表的形式插入,(`sunwukong; 150)為一個普通列表
,5
q)`t insert (`sunwukong; 150) /相同的記錄會重復插入
,6
q)t
name iq
-------------
zhangsan 42
lisi 98
wangwu 126
wanger 134
sunwukong 150
sunwukong 150
q)t:3#t /這里3#t表示只取表t的前3行數(shù)據(jù)
q)t
name iq
------------
zhangsan 42
lisi 98
wangwu 126
q)`t insert (`name`iq!(`Slar; 134); (`name`iq!(`Marvin; 200))) /同時插入多個數(shù)據(jù)的第一種方法
3 4
q)t
name iq
------------
zhangsan 42
lisi 98
wangwu 126
Slar 134
Marvin 200
q)t:3#t
q)`t insert ([] name:`Slar`Marvin; iq:134 200) /同時插入多個數(shù)據(jù)的第二種方法,該方法就是將一個表插入到另外一個表中
3 4
q)t
name iq
------------
zhangsan 42
lisi 98
wangwu 126
Slar 134
Marvin 200
q)insert[`t; (`Slar; 134)] /使用前綴的形式來插入數(shù)據(jù)
,5
q)t
name iq
------------
zhangsan 42
lisi 98
wangwu 126
Slar 134
Marvin 200
Slar 134
q)`t insert ((`Prefect; 126); (`Marvin; 200)) /這里同時插入多個數(shù)據(jù)不能以這種形式,因為這是一個嵌套列表,無法跟表的列對應上,因此會報錯
'type
q)`t insert (`Prefect`Marvin; 126 200) /多個數(shù)據(jù)的通過普通列表的插入方式
6 7
q)t
name iq
------------
zhangsan 42
lisi 98
wangwu 126
Slar 134
Marvin 200
Slar 134
Prefect 126
Marvin 200
q)t:([] name:(); iq:()) /創(chuàng)建一個未指定數(shù)據(jù)類型的空表t
q)t
name iq
-------
q)`t insert (`Dent;98) /為制定數(shù)據(jù)類型的空表t的數(shù)據(jù)類型由第一次插入的數(shù)據(jù)類型來決定后續(xù)只能插入那種數(shù)據(jù)類型
,0
q)t
name iq
-------
Dent 98
q)meta t /這時我們可以看書name字段類型是symbol,iq的數(shù)據(jù)類型是long類型
c | t f a
----| -----
name| s
iq | j
q)`t insert (`Beeblebrox; 42.0) /此時我們給表t中插入一條含有float類型的數(shù)據(jù)則添加失敗
'type
q)tnew /我們可以看是否有一個表叫tnew的,返回結(jié)果錯誤,表示內(nèi)存中目前不包含這個表
'tnew
q)`tnew insert enlist `c1`c2!(`a; 10) /此時我們給未曾創(chuàng)建的tnew表中插入數(shù)據(jù),Q會自動來創(chuàng)建tnew表并添加對應數(shù)據(jù)
,0
q)tnew
c1 c2
-----
a 10
q)`c1`c2!(`a; 10) /這是一個字典
c1| `a
c2| 10
q)enlist `c1`c2!(`a; 10) /因此我們需要用enlist轉(zhuǎn)換成表才能成功`tnew insert enlist `c1`c2!(`a; 10)這個操作
c1 c2
-----
a 10
q)kt:([eid:1001 1002 1003] name:`Dent`Beeblebrox`Prefect; iq:98 42 126) /創(chuàng)建一個含有主鍵的kt表,主鍵是eid
q)kt
eid | name iq
----| --------------
1001| Dent 98
1002| Beeblebrox 42
1003| Prefect 126
q)kt_foreign:([] eid:`kt$1003 1002 1001 1002 1001; sc:126 36 92 39 98) /創(chuàng)建一個外鍵表kt_foreign,對應的外鍵是kt表的eid主鍵
q)kt_foreign
eid sc
--------
1003 126
1002 36
1001 92
1002 39
1001 98
q)`kt_foreign insert (1002;42) /給含有外鍵的表中插入數(shù)據(jù)
,5
q)kt_foreign
eid sc
--------
1003 126
1002 36
1001 92
1002 39
1001 98
1002 42
q)`kt_foreign insert (1004;42) /同樣當kt表中的eid主鍵不包含1004這個記錄時,給kt_foreign表中添加1004這條數(shù)據(jù)也不會成功
'cast
q)kt:([eid:1001 1002] name:`Dent`Beeblebrox; iq:98 42) /創(chuàng)建一個含有主鍵的kt表,主鍵是eid
q)kt
eid | name iq
----| -------------
1001| Dent 98
1002| Beeblebrox 42
q)`kt insert (1005; `Marvin; 200) /給kt表中添加數(shù)據(jù)
,2
q)`kt insert (1004;`Slartibartfast;158)
,3
q)`kt insert (1004;`Slar;158) /同樣插入的數(shù)據(jù)eid字段中包含該記錄(1004)時,插入會失敗
'insert
q)kt,:(1004;`sla;158) /但是該方式就會成功
q)kt
eid | name iq
----| --------------
1001| Dent 98
1002| Beeblebrox 42
1005| Marvin 200
1004| sla 158
3. upsert插入
upsert與insert相似,只是upsert在含有主鍵的表上比insert插入方式更加靈活。
q)t:([] name:`Dent`Beeblebrox`Prefect; iq:42 98 126)
q)t
name iq
--------------
Dent 42
Beeblebrox 98
Prefect 126
q)`t upsert (`name`iq)!(`sla;134) /upsert的字典插入形式
`t
q)t
name iq
--------------
Dent 42
Beeblebrox 98
Prefect 126
sla 134
q)`t upsert (`Marvin; 150) /upsert的列表插入形式
`t
q)t
name iq
--------------
Dent 42
Beeblebrox 98
Prefect 126
sla 134
Marvin 150
q)`t upsert ([] name:`Slartibartfast`Marvin; iq:134 200) /upsert的表的插入形式
`t
q)t
name iq
------------------
Dent 42
Beeblebrox 98
Prefect 126
sla 134
Marvin 150
Slartibartfast 134
Marvin 200
q)upsert[`t; (`Slartibartfast; 134)] /upsert的前綴插入形式
`t
q)([] c1:`a`b; c2:10 20) upsert (`c; 30) /upsert的獨特插入方式
c1 c2
-----
a 10
b 20
c 30
q)f:{t:([] c1:`a`b; c2:10 20); t upsert x} /我們可以把upsert的插入方式寫成函數(shù)腳本的形式,這樣后續(xù)插入的時候就更加方便
q)f(`c;30) /以函數(shù)的形式插入數(shù)據(jù)
c1 c2
-----
a 10
b 20
c 30
q)kt
eid | name iq
----| --------------
1001| Dent 98
1002| Beeblebrox 42
1005| Marvin 200
1004| sla 158
q)`kt upsert (1001; `Beeblebrox; 42) /upsert給含有主鍵的表中插入數(shù)據(jù),其中已經(jīng)包含1001這條數(shù)據(jù),也能夠成功
`kt
q)kt
eid | name iq
----| --------------
1001| Beeblebrox 42
1002| Beeblebrox 42
1005| Marvin 200
1004| sla 158
q)`kt upsert (1001; `Beeblebrox; 43) /當主鍵中存在1001這條數(shù)據(jù)時,再次插入這條數(shù)據(jù)就是更新了,而不是insert的不能插入
`kt
q)kt
eid | name iq
----| --------------
1001| Beeblebrox 43
1002| Beeblebrox 42
1005| Marvin 200
1004| sla 158
二、 表的數(shù)據(jù)查詢(select語句)
在本節(jié)中,我們將分享select查詢語句,select查詢語句包含必要參數(shù)和可選參數(shù),最終解釋器轉(zhuǎn)換為函數(shù)形式,并應用于表查詢后的返回結(jié)果也是表。雖然select類似于類似SQL語句的語法和行為,但潛在的機制卻截然不同。
我們詳細研究了每個組成部分select。通過實際案例來分析。
該select查詢語句具有以下形式:
select< ps > <bypb >fromtexp <wherepw >
在select和from關鍵字是必需的; texp為表的名稱。其余元素ps,pb和pw是可選的。它們分別稱為select,by和where子句。這里還要注意分隔子句的逗號的使用,具體見案例。這里from表達式texp(主要是表的名稱);where子句pw(主要是限制條件等);by子句pb(主要是by的聚合);select子句ps(主要列的選擇)。
Select語句的執(zhí)行順序是:

1. select子句
q)t:([] c1:`a`b`c; c2:10 20 30; c3:1.1 2.2 3.3)
q)t /查詢表t的所有內(nèi)容
c1 c2 c3
---------
a 10 1.1
b 20 2.2
c 30 3.3
q)select from t /查詢表t的所有內(nèi)容,而SQL中是select * from t
c1 c2 c3
---------
a 10 1.1
b 20 2.2
c 30 3.3
q)t~select from t /這兩種查詢方式是一樣的
1b
q)select c1, c3 from t /查詢表t中的c1列和c3列的所有內(nèi)容
c1 c3
------
a 1.1
b 2.2
c 3.3
q)select avg c2 from t /我們也可以同時使用內(nèi)置函數(shù)來操作查詢結(jié)果,這里返回c2字段的平均值
c2
--
20
q)select c1, res:2*c2 from t /查詢表t中c1列和c2列,并給c2列所有值乘以2然后將該列重命名為res。這里并不會改變表t的內(nèi)容
c1 res
------
a 20
b 40
c 60
當我們查詢語句中的列名重復時,系統(tǒng)會自動重命名,重命名的方式就是名稱后面加一個1(如c1和c11);當有表達式時(c2+c3)系統(tǒng)會自動以第一個列名作為返回的列名,而不是以表達式命名;若表達式第一個不是列名,則以x作為返回的列名(如2*c2),同理多個這樣的表達式則為x,x1,x2等形式。下面的兩個查詢語句可以仔細領會一下。
q)select c1, c1, 2*c2, c2+c3, string c3 from t
c1 c11 x c2 c3
--------------------
a a 20 11.1 "1.1"
b b 40 22.2 "2.2"
c c 60 33.3 "3.3"
q)select c1, c1, c1, 2*c2, 2*c2, c2+c3, c3+c2, 2%c3, c2%c3, string c3 from t
c1 c11 c12 x x1 c2 c3 x2 c21 c31
---------------------------------------------------
a a a 20 20 11.1 11.1 1.818182 9.090909 "1.1"
b b b 40 40 22.2 22.2 0.9090909 9.090909 "2.2"
c c c 60 60 33.3 33.3 0.6060606 9.090909 "3.3"
Q的表中含有一個虛擬列i,虛擬列i表示表中每條記錄的行號。
q)select i, c1 from t /這里虛擬列i不能直接返回一個i作為返回的列名,用x來自動重命名。
x c1
----
0 a
1 b
2 c
q)select ix:i, c1 from t /我們可以給虛擬列i重命名
ix c1
-----
0 a
1 b
2 c
q)t1:([] c1:`a`b`a; c2:10 20 10)
q)select distinct from t1 /我們可以使用distinct關鍵字來進行查詢結(jié)果去掉重復的內(nèi)容
c1 c2
-----
a 10
b 20
q)show tnest:([] c1:`a`b`c; c2:(10 20 30; enlist 40; 50 60))
c1 c2
-----------
a 10 20 30
b ,40
c 50 60
q)select avg c2 from tnest /這里由于tnest表的c2字段值不是簡單列表,因此無法直接使用內(nèi)置原子函數(shù)avg(求平均值),需要用each修飾符
'length
q)select avg each c2 from tnest /使用了each修飾符之后就能夠查詢并計算成功
c2
--
20
40
55
q)update c3:(1.1 2.2 3.3; enlist 4.4; 5.5 6.6) from `tnest /這里使用update給表tnest增加一列,后面會針對性的講解update操作
`tnest
q)tnest
c1 c2 c3
-----------------------
a 10 20 30 1.1 2.2 3.3
b ,40 ,4.4
c 50 60 5.5 6.6
q)select wtavg:c2 wavg' c3 from tnest /這里wtavg:c2 wavg' c3表示求加權(quán)平均,c2列的值為權(quán)重
wtavg
--------
2.566667
4.4
6.1
2. where的過濾條件
與SQL語言相似,條件查詢也是使用where關鍵字。where后面一般跟的都是條件設置
q)t:([] c1:`a`b`c; c2:10 20 30; c3:1.1 2.2 3.3)
q)t
c1 c2 c3
---------
a 10 1.1
b 20 2.2
c 30 3.3
q)select from t where c2>15 /限制條件為c2字段中的值大于15的記錄
c1 c2 c3
---------
b 20 2.2
c 30 3.3
q)t where t[`c2]>15 /一種較為簡便的where查詢方式
c1 c2 c3
---------
b 20 2.2
c 30 3.3
q)select from t where 011b /限制條件也可以是布爾值,從第0行開始,1代表選中,0代表不選中該行,如010b表示選中第二行
c1 c2 c3
---------
b 20 2.2
c 30 3.3
q)tbig:100#t /將100#t表示將表t按照順序復制100行,則是100%3=33余1,也就是33個表t加第一行
q)tbig
c1 c2 c3
---------
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
.. /省略號表示未顯示完全
q)select from tbig where i within 50 99 /也可以利用虛擬列i來作為限制條件,within限制條件是取50~99之間的行
c1 c2 c3
---------
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
b 20 2.2
c 30 3.3
a 10 1.1
..
q)select from tbig where i within 50 52
c1 c2 c3
---------
c 30 3.3
a 10 1.1
b 20 2.2
q)s:50
q)e:52
q)select from tbig where i within (s;e) /這里within也可以使用參數(shù)的形式
c1 c2 c3
---------
c 30 3.3
a 10 1.1
b 20 2.2
q)select from t where c2>15,c3<3.0 /同時多個限制條件,這里的“,”號表示和的意思
c1 c2 c3
---------
b 20 2.2
q)select from t where (c2>15)&c3<3.0 /使用&符號時這里的括號就是必須的了
c1 c2 c3
---------
b 20 2.2
q)t:([] c1:00:00:00.000+til 1000000; c2:1000000?`a`b; c3:1000000?100.)
q)t
c1 c2 c3
------------------------
00:00:00.000 a 39.27524
00:00:00.001 a 51.70911
00:00:00.002 a 51.59796
00:00:00.003 a 40.66642
00:00:00.004 b 17.80839
00:00:00.005 b 30.17723
00:00:00.006 a 78.5033
00:00:00.007 a 53.47096
00:00:00.008 a 71.11716
00:00:00.009 a 41.1597
00:00:00.010 a 49.31835
00:00:00.011 a 57.85203
00:00:00.012 b 8.388858
00:00:00.013 a 19.59907
00:00:00.014 a 37.5638
00:00:00.015 b 61.37452
00:00:00.016 a 52.94808
00:00:00.017 b 69.16099
00:00:00.018 b 22.96615
00:00:00.019 a 69.19531
..
q)\t select from t where c1 within 00:00:01.000 00:00:01.999, c2=`a /多個限制條件查詢時,不同的順序查詢的時間是不同個的,這里\t為顯示執(zhí)行這條語句的時間,結(jié)果是1秒
1
q)\t select from t where c2=`a, c1 within 00:00:01.000 00:00:01.999 /同樣的限制條件,但是順序不同,這里的時間就是12秒了
12
對于表的中某一個字段不是簡單列表時,使用where限制條件與前面一樣,也是需要用到each修飾符
q)t:([] f:1.1 2.2 3.3; s:("abc";enlist "d";"ef"))
q)t
f s
---------
1.1 "abc"
2.2 ,"d"
3.3 "ef"
q)select from t where s="ef" /這里只是判斷字段s是否等于“ef”
'length
q)select from t where s~"ef" /這里只是判斷字段s是否能與“ef”匹配
f s
---
q)select from t where s~\:"ef" /這里\:是前面介紹的each-left,讓”ef”來匹配s字段中的每一個值
f s
--------
3.3 "ef"
q)select from t where s like "ef" /當然我們也可以使用like關鍵字,這樣更加方便
f s
--------
3.3 "ef"
這里為了方便,我就直接引入了官方給定的案例表格,可以通過下面的方式導入腳本。導入后內(nèi)存中就會創(chuàng)建三個表,分別是表s,p和sp。
q)\l /Users/souosamusan/q/sp.q /腳本的導入方式,通過該腳本創(chuàng)建三個表,分別是表s,p和sp
q)s /表s
s | name status city
--| -------------------
s1| smith 20 london
s2| jones 10 paris
s3| blake 30 paris
s4| clark 20 london
s5| adams 30 athens
q)p /表p
p | name color weight city
--| -------------------------
p1| nut red 12 london
p2| bolt green 17 paris
p3| screw blue 17 rome
p4| screw red 14 london
p5| cam blue 12 paris
p6| cog red 19 london
q)sp /表sp
s p qty
---------
s1 p1 300
s1 p2 200
s1 p3 400
s1 p4 200
s4 p5 100
s1 p6 100
s2 p1 300
s2 p2 400
s3 p2 200
s4 p2 200
s4 p4 300
s1 p5 400
q)meta s /查看表s的結(jié)構(gòu)信息
c | t f a
------| -----
s | s
name | s
status| j
city | s
q)meta p /查看表p的結(jié)構(gòu)信息
c | t f a
------| -----
p | s
name | s
color | s
weight| j
city | s
q)meta sp /查看表sp的結(jié)構(gòu)信息,sp有兩個外鍵,分別來自表s和表p
c | t f a
---| -----
s | s s
p | s p
qty| j
q)select[2] from s where city<>`athens /這里的限制條件時不等于,同時select[2]表示只取查詢結(jié)果的前兩條數(shù)據(jù)
s | name status city
--| -------------------
s1| smith 20 london
s2| jones 10 paris
q)select[-1] from s where city<>`athens /這里的限制條件時不等于,同時select[-1]表示只取查詢結(jié)果的倒數(shù)第一條數(shù)據(jù)
s | name status city
--| -------------------
s4| clark 20 london
q)select from s where city<>`athens /這里的限制條件是不等于
s | name status city
--| -------------------
s1| smith 20 london
s2| jones 10 paris
s3| blake 30 paris
s4| clark 20 london
q)2#select from s where city<>`athens 這里的限制條件時不等于,同時2#表示只取查詢結(jié)果的前兩條數(shù)據(jù)
s | name status city
--| -------------------
s1| smith 20 london
s2| jones 10 paris
q)-1#select from s where city<>`athens /這里的限制條件時不等于,同時-1#表示只取查詢結(jié)果的倒數(shù)第一條數(shù)據(jù)
s | name status city
--| -------------------
s4| clark 20 london
q)select[1 2] from s where city<>`athens /這里的限制條件時不等于,同時select[1 2]表示只取查詢結(jié)果的第2行和第3行數(shù)據(jù)
s | name status city
--| ------------------
s2| jones 10 paris
s3| blake 30 paris
q)select[>name] from s where city<>`athens /這里的限制條件時不等于,同時select[>name]表示將查詢結(jié)果的按照name字段中的降序(字母z-a)排列
s | name status city
--| -------------------
s1| smith 20 london
s2| jones 10 paris
s4| clark 20 london
s3| blake 30 paris
q)select[<city] from s where city<>`athens /這里的限制條件時不等于,同時select[<city]表示將查詢結(jié)果的按照city字段中的升序(字母a-z)排列
s | name status city
--| -------------------
s1| smith 20 london
s4| clark 20 london
s2| jones 10 paris
s3| blake 30 paris
q)select[2; >name] from s where city<>`athens /這里的限制條件時不等于,同時select[2;>name]表示將查詢結(jié)果的按照name字段中的降序(字母z-a)排列并且只取前兩條數(shù)據(jù)
s | name status city
--| -------------------
s1| smith 20 london
s2| jones 10 paris
q)p
p | name color weight city
--| -------------------------
p1| nut red 12 london
p2| bolt green 17 paris
p3| screw blue 17 rome
p4| screw red 14 london
p5| cam blue 12 paris
p6| cog red 19 london
在SQL中你會使用HAVING,但Q語言中沒有HAVING子句。而是fby在where短語中使用。由于它返回每個組中聚合的值,因此只需將查詢目標列與fby結(jié)果進行比較,最后就可以返回想要的結(jié)果。
(fagg ; exprcol)fby c
括號中的操作數(shù)包含兩項,包括一個聚合函數(shù)fagg 和一個列的表達式。c是要分組的列。
q)select from p where weight=(max;weight) fby city /這里首先時fby將city字段進行合并,相當于把所有city字段中相同的值作為一組,然后weight=(max;weight)再去進行匹配查找相關記錄
p | name color weight city
--| -------------------------
p2| bolt green 17 paris
p3| screw blue 17 rome
p6| cog red 19 london
q)select from p where weight=(max;weight) fby city, color=`blue /這里首先時fby將city字段進行合并,并返回color字段中值為blue的疾苦,然后weight=(max;weight)再去進行匹配查找相關記錄
p | name color weight city
--| -----------------------
p3| screw blue 17 rome
q)select max weight by city from p /使用內(nèi)置函數(shù)查詢max weight表示選擇weight中最大的值返回,by子句是分組查詢,by city就是先將city字段中的相同值都放在一起,然后max weigh去查找每組中最大的weight
city | weight
------| ------
london| 19
paris | 17
rome | 17
q)select name, color, max weight by city from p /使用內(nèi)置函數(shù)查詢,并結(jié)合by子句分組
city | name color weight
------| ----------------------------------
london| `nut`screw`cog `red`red`red 19
paris | `bolt`cam `green`blue 17
rome | ,`screw ,`blue 17
q)select first name, first color, max weight by city from p /使用內(nèi)置函數(shù)查詢,by city分組后再去查詢first name, first color, max weight等結(jié)果
city | name color weight
------| ------------------
london| nut red 19
paris | bolt green 17
rome | screw blue 17
3. 分組與聚合
在SQL中,分組和聚合是一起執(zhí)行,在Q語言中它們是獨立的。在本節(jié)中,我們使用sp.q腳本中定義的s、p和sp表。
q)s
s | name status city
--| -------------------
s1| smith 20 london
s2| jones 10 paris
s3| blake 30 paris
s4| clark 20 london
s5| adams 30 athens
q)p
p | name color weight city
--| -------------------------
p1| nut red 12 london
p2| bolt green 17 paris
p3| screw blue 17 rome
p4| screw red 14 london
p5| cam blue 12 paris
p6| cog red 19 london
q)sp
s p qty
---------
s1 p1 300
s1 p2 200
s1 p3 400
s1 p4 200
s4 p5 100
s1 p6 100
s2 p1 300
s2 p2 400
s3 p2 200
s4 p2 200
s4 p4 300
s1 p5 400
1) 無分組的聚合
Q語言中提供了很多的聚合函數(shù),如sum、avg、max和min。我們可以直接將這些聚合函數(shù)用于整個表,不進行分組,這里就可以得到整個表的一些想要查的信息。
q)select total:sum qty, mean:avg qty from sp /將聚合函數(shù)用于整個表中
total mean
--------------
3100 258.3333
2) 無聚合的分組
我們可以用子句來將一個表中某些字段中具有相同的數(shù)據(jù)的值進行分組,非常類似于SQL中的group by子句。含有by子句的查詢結(jié)果是一個由主鍵的表,其中主鍵是所分組的列。
q)t:([] c1:`a`b`a`b`c; c2:10 20 30 40 50)
q)t
c1 c2
-----
a 10
b 20
a 30
b 40
c 50
q)select c2 by c1 from t /將c2的值由c1進行分組,結(jié)果為c1是主鍵的一張表
c1| c2
--| -----
a | 10 30
b | 20 40
c | ,50
q)ungroup select c2 by c1 from t /我們也可以使用ungroup關鍵字將分組的結(jié)果進行解組
c1 c2
-----
a 10
a 30
b 20
b 40
c 50
q)sp
s p qty
---------
s1 p1 300
s1 p2 200
s1 p3 400
s1 p4 200
s4 p5 100
s1 p6 100
s2 p1 300
s2 p2 400
s3 p2 200
s4 p2 200
s4 p4 300
s1 p5 400
q)`p xgroup sp /還有最快捷的方法,我們直接使用xgroup進行分組,而不需要使用select關鍵字
p | s qty
--| -------------------------------
p1| `s$`s1`s2 300 300
p2| `s$`s1`s2`s3`s4 200 400 200 200
p3| `s$,`s1 ,400
p4| `s$`s1`s4 200 300
p5| `s$`s4`s1 100 400
p6| `s$,`s1 ,100
q)`qty xgroup sp /直接使用xgroup關鍵字來進行分組
qty| s p
---| -------------------------------
300| `s$`s1`s2`s4 `p$`p1`p1`p4
200| `s$`s1`s1`s3`s4 `p$`p2`p4`p2`p2
400| `s$`s1`s2`s1 `p$`p3`p2`p5
100| `s$`s4`s1 `p$`p5`p6
q)ungroup `p xgroup sp /同樣也可以使用ungroup進行解組,這里注意解組后的表的信息,將會按照一定的順序排列
p s qty
---------
p1 s1 300
p1 s2 300
p2 s1 200
p2 s2 400
p2 s3 200
p2 s4 200
p3 s1 400
p4 s1 200
p4 s4 300
p5 s4 100
p5 s1 400
p6 s1 100
3) 有聚合的分組
我們也可以將分組后的結(jié)果進行聚合操作,最后的返回結(jié)果也是一個還有主鍵的表。
q)select sum c2 by c1 from t /使用by子句進行分組,并使用聚合函數(shù)sum
c1| c2
--| --
a | 40
b | 60
c | 50
q)t:([] desk:`a`b`a`b`a`b; acct:`1`2`3`4`1`4; pnl:1.1 -2.2 3.3 4.4 5.5 -.5)
q)t
desk acct pnl
--------------
a 1 1.1
b 2 -2.2
a 3 3.3
b 4 4.4
a 1 5.5
b 4 -0.5
q)select ct:count desk, sum pnl by desk, acct from t /也可以指定多個用于分組的字段,同時也可以進行聚合操作
desk acct| ct pnl
---------| -------
a 1 | 2 6.6
a 3 | 1 3.3
b 2 | 1 -2.2
b 4 | 2 3.9
q)select by desk from t /這里可以直接省略<Ps>子句,這樣直接返回每個組的最后一條數(shù)據(jù),這對金融行業(yè)也非常有用,比如可能需要查詢最新的價格
desk| acct pnl
----| ---------
a | 1 5.5
b | 4 -0.5
q)t:([] c1:00:00:00.000+til 1000000; c2:1000000?`a`b; c3:1000000?100)
q)t
c1 c2 c3
------------------------
00:00:00.000 a 39.27524
00:00:00.001 a 51.70911
00:00:00.002 a 51.59796
00:00:00.003 a 40.66642
00:00:00.004 b 17.80839
00:00:00.005 b 30.17723
00:00:00.006 a 78.5033
00:00:00.007 a 53.47096
00:00:00.008 a 71.11716
00:00:00.009 a 41.1597
00:00:00.010 a 49.31835
00:00:00.011 a 57.85203
00:00:00.012 b 8.388858
00:00:00.013 a 19.59907
00:00:00.014 a 37.5638
00:00:00.015 b 61.37452
00:00:00.016 a 52.94808
00:00:00.017 b 69.16099
00:00:00.018 b 22.96615
00:00:00.019 a 69.19531
..
q)select avg c3 by 100 xbar c1,c2 from t /也可以使用帶有表達式的分組操作,這里100 xbar表示以100的整數(shù)倍為步長增加
c1 c2| c3
---------------| --------
00:00:00.000 a | 55.26494
00:00:00.000 b | 41.81758
00:00:00.100 a | 48.88826
00:00:00.100 b | 46.10946
00:00:00.200 a | 53.72272
00:00:00.200 b | 51.42873
00:00:00.300 a | 54.53996
00:00:00.300 b | 49.50472
00:00:00.400 a | 51.95785
00:00:00.400 b | 53.63795
00:00:00.500 a | 55.24681
00:00:00.500 b | 58.08108
00:00:00.600 a | 40.27698
00:00:00.600 b | 53.36846
00:00:00.700 a | 46.88679
00:00:00.700 b | 50.91821
00:00:00.800 a | 54.62589
00:00:00.800 b | 58.76686
00:00:00.900 a | 53.28107
00:00:00.900 b | 48.06001
..
4. exec關鍵字
我們知道select查詢最后返回的是一張表,所以每個字段的行數(shù)是一樣的,但是有時候可能想同時進行多個查詢操作,最后每個<Ps>子句可能行數(shù)不一樣,這時就會報錯,因此可以使用exec關鍵字來進行查詢,其結(jié)果返回是一個列表或者字典
q)t:([] name:`a`b`c`d`e; state:`NY`FL`OH`NY`HI)
q)t
name state
----------
a NY
b FL
c OH
d NY
e HI
q)select name, distinct state from t /由于name, distinct state兩個結(jié)果行數(shù)不想等,因此查詢失敗
'length
q)exec name, distinct state from t /使用exec查詢成功,結(jié)果返回的是一個字典
name | `a`b`c`d`e
state| `NY`FL`OH`HI
q)exec distinct state from t /對于單個<Ps>子句其返回結(jié)果是一個列表
`NY`FL`OH`HI
q)select distinct state from t /select查詢返回的結(jié)果是一張表
state
-----
NY
FL
OH
HI
三、 表的數(shù)據(jù)更新
表的數(shù)據(jù)更新,我們使用update關鍵字來進行更新,跟新的語法模版如下:
update< pu > <bypb >fromtexp <wherepw >
update的語法模板于select類似,只是< pu >為要更新的具體值。如果<Pu>指定的列是表中存在的列,則更新該列;如果<Pu>指定的列是表中不存在的列,則將該列添加到列表的末尾。其他子句于select一樣。
q)t:([] c1:`a`b`c; c2:10 20 30)
q)t
c1 c2
-----
a 10
b 20
c 30
q)update c1:`x`y`z from t /更新的c1列在表中有,則更新對應的列
c1 c2
-----
x 10
y 20
z 30
q)t
c1 c2
-----
a 10
b 20
c 30
q)update c3:`x`y`z from t /更新的c3列在表中沒有,則直接在表中添加新列,直接添加在表的右側(cè)
c1 c2 c3
--------
a 10 x
b 20 y
c 30 z
q)t /前面的更新并沒有更新原表t,而是生成了一個新表
c1 c2
-----
a 10
b 20
c 30
q)update c3:`x`y`z from `t /要想更新原表t則需要傳遞表名的形式(`t)
`t
q)t
c1 c2 c3
--------
a 10 x
b 20 y
c 30 z
q)update c2:c2+100 from t /也可以使用表達式的形式更新
c1 c2 c3
---------
a 110 x
b 120 y
c 130 z
q)update c2+100 from t /使用表達式的第二種更新形式
c1 c2 c3
---------
a 110 x
b 120 y
c 130 z
q)t:([] c1:`a`b`c; c2:10 20 30)
q)update c3:42 from t /更新的數(shù)據(jù)自動匹配所有行
c1 c2 c3
--------
a 10 42
b 20 42
c 30 42
q)t
c1 c2
-----
a 10
b 20
c 30
q)update c2:c2+100 from t where c1<>`a /使用where條件更新
c1 c2
------
a 10
b 120
c 130
q)update c3:1b from t where c2>15 /使用where進行條件更新
c1 c2 c3
--------
a 10 0
b 20 1
c 30 1
q)t
c1 c2
-----
a 10
b 20
c 30
q)update c2:42 43 from t where c2>15 /使用where進行條件更新
c1 c2
-----
a 10
b 42
c 43
q)update c2:42 43 44 from t where c2>15 /由于更新的值與條件結(jié)果的行數(shù)不匹配,出現(xiàn)長度錯誤
'length
q)update c2:42 43 from t /由于更新的值與條件結(jié)果的行數(shù)不匹配,出現(xiàn)長度錯誤
'length
q)update c2:42.0 43 from t where c2>15 /由于更新的值與字段的類型不匹配,出現(xiàn)類型錯誤
'type
q)p
p | name color weight city
--| -------------------------
p1| nut red 12 london
p2| bolt green 17 paris
p3| screw blue 17 rome
p4| screw red 14 london
p5| cam blue 12 paris
p6| cog red 19 london
q)update avg weight by city from p /復合更新操作,包含分組,聚會操作
p | name color weight city
--| -------------------------
p1| nut red 15 london
p2| bolt green 14.5 paris
p3| screw blue 17 rome
p4| screw red 15 london
p5| cam blue 14.5 paris
p6| cog red 15 london
四、 表的數(shù)據(jù)刪除
與SQL相似,表的刪除為delete關鍵字,可以刪除行和列。delete的刪除語法如下:
delete< pcols > from texp < where pw >
< pcols >為表的列,texp為表的名稱,< where pw >為刪除的限制條件,這里需要注意,< pcols >和< where pw >不能同時存在。
q)t:([] c1:`a`b`c; c2:10 20 30)
q)t
c1 c2
-----
a 10
b 20
c 30
q)delete c1 from t /刪除c1列從表中。這里注意會將整個c1列刪除,包括列名
c2
--
10
20
30
q)t
c1 c2
-----
a 10
b 20
c 30
q)delete from t where c2>15 /條件刪除
c1 c2
-----
a 10
q)delete from t where c2=30 /條件刪除
c1 c2
-----
a 10
b 20
q)t /查詢表t發(fā)現(xiàn)所有的內(nèi)容都還在,因此刪除原表需要傳遞名稱的形式
c1 c2
-----
a 10
b 20
c 30
q)delete c1 from `t /通過傳遞名稱(`t)形式在原表中刪除
`t
q)t
c2
--
10
20
30
q)t:([] c1:1 2; c2:`a`b; c3:1.1 2.2; c4:2015.01.01 2015.01.02)
q)t
c1 c2 c3 c4
--------------------
1 a 1.1 2015.01.01
2 b 2.2 2015.01.02
q)(select c1,c2,c4 from t)~(delete c3 from t) /可以發(fā)現(xiàn)者兩條結(jié)果是一樣的,因此我們可以充分利用標的查詢與刪除的特性
1b
q)select c1,c2,c4 from t
c1 c2 c4
----------------
1 a 2015.01.01
2 b 2015.01.02
q)delete c3 from t
c1 c2 c4
----------------
1 a 2015.01.01
2 b 2015.01.02