一、 表的排序

我們知道表的欄位中的值其實是由列表組成,因此具有固有的順序。但是我們也可以進行排序操作的,只是Q語言中沒有order by的子句,

我們可以直接使用xasc和xdesc,同時兩個也可以同時使用進行混合排序。

q)t:([] c1:`a`b`c`a; c2:20 10 40 30)
q)t
c1 c2
-----
a 20
b 10
c 40
a 30
q)`c2 xasc t /給表t進行升序排序
c1 c2
-----
b 10
a 20
a 30
c 40
q)`c1`c2 xasc t /給表t中的c1列和c2列同時進行升序排序,但是不是分開單獨進行排序,而是聯合起來排序
c1 c2
-----
a 20
a 30
b 10
c 40
q)t /此時我們發現原表t並沒有排序,因此表的操作要改表原表都是需要傳遞表的名稱(`table_name)的形式來操作
c1 c2
-----
a 20
b 10
c 40
a 30
q)`c1`c2 xasc `t /傳遞表的名稱的形式來排序,返回的結果是表的名稱
`t
q)t
c1 c2
-----
a 20
a 30
b 10
c 40
q)`c1`c2 xdesc t /給表t中的c1列和c2列同時進行降序排序,但是不是分開單獨進行排序,而是聯合起來排序
c1 c2
-----
c 40
b 10
a 30
a 20
q)t
c1 c2
-----
a 20
a 30
b 10
c 40
q)`c1 xasc `c2 xdesc t /同時也可以對錶進行升序和降序排列操作,但是注意並不是將兩個列單獨,也是聯合排序,有點類似於分組排序一樣
c1 c2
-----
a 30
a 20
b 10
c 40

二、 表的重命名

有時候我們可能需要對一個表的欄位名進行重新命名,欄位的名稱重新命名的語法如下:

@[cols[table_name]; where cols[table_name]=`old_name; :; `new_name] xcol table_name

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)@[cols[t]; where cols[t]=`c2; :; `new2] xcol t /將欄位c2的列名改為new2,注意這裡的冒號是必要的,相當於整個的意思
c1 new2 c3
-----------
a 10 1.1
b 20 2.2
c 30 3.3
q)@[cols[t]; where cols[t] in `c1`c3; :; `new1`new3] xcol t /當然也可以同時修改多個欄位的名稱
new1 c2 new3
------------
a 10 1.1
b 20 2.2
c 30 3.3
q)`new1`new2 xcol t /當然如果修改的欄位名是從左往右依次修改的,則可以使用這種簡便的形式
new1 new2 c3
-------------
a 10 1.1
b 20 2.2
c 30 3.3

三、 表的聯接查詢

關係資料庫設計的本質是使用關係和鍵對數據進行規範化,然後使用連接進行重組。規範化消除了重複數據,這佔用了空間並且難以保持一致。聯接恢復原始的扁平矩形形式,

使數據易於使用(電子表格如此受歡迎的原因)。

在SQL中,具有主鍵和外鍵的關係結構是靜態的。必須先使用單獨的語言(DDL)定義數據才能使用數據。必須預先建立外鍵/主鍵關係才能進行連接。

在Q中,表是該語言中的第一類實體。你可以靜態定義表和關係,也可以輕鬆地動態創建它們。甚至可以連接可能具有關係但不具有關係的表。

聯接可以分為內部或外部。內聯僅對具有匹配的兩個操作數中的值進行配對。外聯分為左外聯和右外聯。

大多數連接是equijoins,意味著鍵必須相等。在Q也有非等值連接,稱為as of joins,其中一個鍵被用於測試低於或-等於針對另一個表中的鍵。

1. 隱式聯接查詢

隱式聯接的操作語法如下:

select cold,k.colm from d

其中cold,k.colm為表d和表m中的相關列。

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)select sname:s.name,qty from sp /查詢sp表的s欄位和qty欄位,同時聯接到s表中的name欄位返回對應的名稱,這時我們看到返回的結果中sp中的s欄位與s表中的name欄位
/通過主鍵和外鍵的關係進行了匹配後返回對應的name
sname qty
---------
smith 300
smith 200
smith 400
smith 200
clark 100
smith 100
jones 300
jones 400
blake 200
clark 200
clark 300
smith 400
q)select sname:s.name, pname:p.name, qty from sp /與上面類似,此次查詢多了p欄位的聯接查詢
sname pname qty
---------------
smith nut 300
smith bolt 200
smith screw 400
smith screw 200
clark cam 100
smith cog 100
jones nut 300
jones bolt 400
blake bolt 200
clark bolt 200
clark screw 300
smith cam 400
q)emaster:([eid:1001 1002 1003 1004 1005] currency:`gbp`eur`eur`gbp`eur)
q)update eid:`emaster$1001 1002 1005 1004 1003 from `s /將emaster表中的eid列添加到表s中,並且作為表s的一個外鍵
`s
q)emaster
eid | currency
----| --------
1001| gbp
1002| eur
1003| eur
1004| gbp
1005| eur
q)meta s /查看錶s的結構信息
c | t f a
------| -----------
s | s
name | s
status| j
city | s
eid | j emaster
q)s
s | name status city eid
--| ------------------------
s1| smith 20 london 1001
s2| jones 10 paris 1002
s3| blake 30 paris 1005
s4| clark 20 london 1004
s5| adams 30 athens 1003
q)select s.name, qty, s.eid.currency from sp /我們可以聯接到表s的eid列,再通過eid列聯接到表emaster的currency列
name qty currency
------------------
smith 300 gbp
smith 200 gbp
smith 400 gbp
smith 200 gbp
clark 100 gbp
smith 100 gbp
jones 300 eur
jones 400 eur
blake 200 eur
clark 200 gbp
clark 300 gbp
smith 400 gbp

2. 臨時左聯查詢(lj)

lj聯接對於有外鍵的表的操作非常有效,同時對於操作的兩個聯接的表如果沒有外鍵關係,也可以進行聯接查詢操作。lj操作語法如下:

left_table lj right_table

right_table是一個含有主鍵的表(目標),left_table是一個普通表或含有主鍵的表(),left_table具有right_table的外鍵或與right_table表中名稱和類型匹配的列。

結果是left_table的所有記錄和增加了匹配上的right_table的記錄。對於left_table中沒有的記錄,會用空值代替。

q)t:([] k:1 2 3 4; c:10 20 30 40)
q)t
k c
----
1 10
2 20
3 30
4 40
q)kt:([k:2 3 4 5]; v:200 300 400 500)
q)kt
k| v
-| ---
2| 200
3| 300
4| 400
5| 500
q)t lj kt /左聯接查詢操作,可以看出返回的結果包含了t表的所有數據,增加了kt表中的v列(該列在t表中不存在),並且由於kt表中的k列中沒有1這條記錄,因此對應的v列用空值代替
k c v
--------
1 10
2 20 200
3 30 300
4 40 400
q)kt:([k:1 2 3 4 5]; v1:10 20 30 40 50; v2:1.1 2.2 3.3 4.4 5.5)
q)kt
k| v1 v2
-| ------
1| 10 1.1
2| 20 2.2
3| 30 3.3
4| 40 4.4
5| 50 5.5
q)tf:([] k:`kt$1 2 3 4; c:10 20 30 40) /表tf有一個外鍵,為kt表的k欄位
q)meta tf
c| t f a
-| ------
k| j kt
c| j
q)tf
k c
----
1 10
2 20
3 30
4 40
q)tf lj kt /通過左聯操作查詢,返回了tf表的所有記錄,表tf的k欄位與kt表的k欄位匹配後對應的記錄
k c v1 v2
-----------
1 10 10 1.1
2 20 20 2.2
3 30 30 3.3
4 40 40 4.4
q)select k,c,k.v1,k.v2 from tf /tf lj kt操作查詢與select k,c,k.v1,k.v2 from tf的結果是一樣的,因此通過lj操作更加快捷簡便
k c v1 v2
-----------
1 10 10 1.1
2 20 20 2.2
3 30 30 3.3
4 40 40 4.4
q)t:([] k:1 2 3 4; v:10 20 30 40)
q)kt:([k:2 3 4 5]; v:200 300 400 500)
q)t
k v
----
1 10
2 20
3 30
4 40
q)kt
k| v
-| ---
2| 200
3| 300
4| 400
5| 500
q)t lj kt /當left_table和right_table具有重複的非主鍵列時(該操作具有upsert意義),right_table(目標)列中的值優先於left_table(源)中的值。
k v
-----
1 10
2 200
3 300
4 400

3. 臨時內聯查詢(ij)

ij聯接與lj聯接非常相似,同時對於操作的兩個聯接的表如果沒有外鍵關係,也可以進行聯接查詢操作。ij操作語法如下:

left_table ij right_table

right_table是一個含有主鍵的表(目標),left_table是一個普通表或含有主鍵的表(源),left_table具有right_table的外鍵或與right_table表中名稱和類型完全匹配的列。

返回的結果包含沿著共同的欄位的記錄(或right_table主鍵與left_table相同匹配上的記錄)。

q)t:([] k:1 2 3 4; c:10 20 30 40)
q)kt:([k:2 3 4 5]; v:2.2 3.3 4.4 5.5)
q)t
k c
----
1 10
2 20
3 30
4 40
q)kt
k| v
-| ---
2| 2.2
3| 3.3
4| 4.4
5| 5.5
q)t ij kt /ij聯接查詢,返回的結果為kt中的主鍵k欄位與t表中的k欄位匹配後返回的對應的記錄(主要是k欄位匹配)
k c v
--------
2 20 2.2
3 30 3.3
4 40 4.4
q)t:([] k:1 2 3 4; v:10 20 30 40)
q)kt:([k:2 3 4 5]; v:200 300 400 500)
q)t
k v
----
1 10
2 20
3 30
4 40
q)kt
k| v
-| ---
2| 200
3| 300
4| 400
5| 500
q)t ij kt /對於ij查詢操作,除了匹配的欄位外還有其他的相同欄位時,則相當於upsert操作,right_table會去更新left_table中的記錄
k v
-----
2 200
3 300
4 400
q)kt1:([k:1 2 3 4]; v:10 0N 30 40)
q)kt:([k:2 3 4 5]; v:200 300 400 500)
q)kt1 ij kt
k| v
-| ---
2| 200
3| 300
4| 400

4. 等值聯接查詢(ej)

我們可能有時候聯接查詢的兩張表都不含有主鍵或者外鍵,這時我們通過隱式聯接或者內聯會出現類型不匹配的錯誤,如:

q)t1:([] k:1 2 3 4; c:10 20 30 40)
q)t2:([] k:2 2 3 4 5; c:200 222 300 400 500; v:2.2 22.22 3.3 4.4 5.5)
q)t1
k c
----
1 10
2 20
3 30
4 40
q)t2
k c v
-----------
2 200 2.2
2 222 22.22
3 300 3.3
4 400 4.4
5 500 5.5
q)t1 ij t2 /t1表與t2表進行ij聯接,出現類型錯誤,隱式聯接和內聯都要求right_table都必須是還有主鍵的表
type

因此我們可以通過等值聯接(ej)來進行聯接查詢操作。等值聯接的查詢方式如下:

ej[`table_colmn; table1; table2]

ej聯接查詢的三個參數,第一個為指定table1和table2都含有的欄位名,table1和table2為兩個指定的表。與隱式聯接或內聯一樣一樣,對於重複的列相當於upsert操作,

table2的值會upsert到table1上。

q)ej[`k; t1; t2] /這裡需要注意的是t2中的k有兩條記錄都是2,因此最終的結果會匹配到兩個2的值,但是內聯就只會出現一個2的記錄
k c v
-----------
2 200 2.2
2 222 22.22
3 300 3.3
4 400 4.4
q)ej[`k; t2; t1]
k c v
----------
2 20 2.2
2 20 22.22
3 30 3.3
4 40 4.4
q)t1 ij `k xkey t2 /`k xkey t2為將t2表的k欄位指定為主鍵,再進行內聯,會發現k欄位中只有2這一條記錄
k c v
---------
2 200 2.2
3 300 3.3
4 400 4.4

5. 加聯接查詢(pj)

加聯接可以看作是一個左聯接,會將重複的記錄進行相加,這就要求重複的記錄必須是數字類型中的一種。當你有兩個非鍵列均為數字的相同模式的表時,這非常有用。

q)t:([] k:`a`b`c; a:100 200 300; b:10. 20. 30.; c:1 2 3)
q)kt:([k:`a`b] a:10 20; b:1.1 2.2)
q)t pj kt
k a b c
------------
a 110 11.1 1
b 220 22.2 2
c 300 30 3

6. 合併聯接查詢(uj)

合併聯接查詢(uj)更強大的是它可以垂直組合兩個或多個任意類型的表,但是只能是統一類型的表,如不能將普通表與主鍵表進行聯合查詢。其查詢語句如下:

left_table uj right_table

(uj/)(table_one;……;table_n)

右操作數中的記錄會以如下的方式添加到左操作數中的記錄中。對於右操作數存在而左操作數中不存在的列,結果表會用相同的名稱和類型的新列作為擴展。結果中的初始記錄來源於左操作數,

新列會設為null。右操作數的記錄的欄位值在相應的列下。一個例子勝過千言。

q)t1:([] c1:`a`b`c; c2: 10 20 30)
q)t2:([] c1:`x`y; c3:8.8 9.9)
q)t1
c1 c2
-----
a 10
b 20
c 30
q)t2
c1 c3
------
x 8.8
y 9.9
q)t1 uj t2 /表的聯合查詢,相同欄位會直接追加,不同的欄位會在右側添加為新欄位,沒有的數據用空值代替
c1 c2 c3
---------
a 10
b 20
c 30
x 8.8
y 9.9
q)t1:([] c1:`a`b`c; c2: 10 20 30)
q)t2:([] c1:`a`b`c; c2: 10 20 30)
q)t1 uj t2 /對於不含主鍵的表,兩個表的uj聯合查詢不會進行重複記錄匹配,對於相同的欄位,會直接在表的後面追加
c1 c2
-----
a 10
b 20
c 30
a 10
b 20
c 30
q)t3:([] c1:`e`f`g; c2:50 60 70; c3:5.5 6.6 7.7)
q)t3
c1 c2 c3
---------
e 50 5.5
f 60 6.6
g 70 7.7
q)(uj/)(t1;t2;t3) /多個表的聯合查詢
c1 c2 c3
---------
a 10
b 20
c 30
x 8.8
y 9.9
e 50 5.5
f 60 6.6
g 70 7.7
q)kt1:([k:1 2 3] v1:`a`b`c; v2:10 20 30)
q)kt2:([k:3 4] v2:300 400; v3:3.3 4.4)
q)kt1
k| v1 v2
-| -----
1| a 10
2| b 20
3| c 30
q)kt2
k| v2 v3
-| -------
3| 300 3.3
4| 400 4.4

q)kt1 uj kt2 /兩個含有主鍵的表的聯合查詢,對於有相同主鍵的記錄,右邊的表會更新左邊表中對應的數據
k| v1 v2 v3
-| ----------
1| a 10
2| b 20
3| c 300 3.3 /仔細注意這條數據的更新
4| 400 4.4
q)t1:([] c1:`a`b`c; c2: 10 20 30)
q)kt1:([k:1 2 3] v1:`a`b`c; v2:10 20 30)
q)t1 uj kt1 /不同類型的表進行聯合查詢直接報錯
nyi

7. 非等值聯接查詢(aj與asof)

as-of如此命名是因為人們經常沿時間列查詢另外一個表中較新的值(如在拍賣中,一件商品會有多個報價,但是最終會只有一個交易價格;或者一直股票在收盤前會有多個價格,

但是收盤時只會有一個價格。那有時候我們就想知道在最終交易價格之前的報價會是多少)。因此as-of聯接不是等值聯接,而是匹配小於或者等於當前時間的記錄。aj的語法如下:

aj[` c 1 ...` c n ; t 1 ; t 2 ]

其中t 1t 2 要聯接的表,`c 1 ...`c n 為兩個表中共有的欄位。這裡不要求要聯接的列為主鍵,但是如果是的話,速度會更快。返回的結果中包含了兩個表中的所有的欄位。

aj語義為:除了最後一列,所有指定的欄位的匹配都是基於等值匹配。假設在兩個表中都存在一個cn這個欄位,給定一個 t1 中的cn,就會在t2中根據小於或等於給定值匹配選擇一個最大值。

尤其是,當cn列作為時間序列值時,對於於t1中的每個cn值,匹配選擇其cnt2值在「 t1 」最新的一條記錄。

我們可以看如下的例子:

q)show t:([] ti:10:01:01 10:01:03 10:01:04;sym:`msft`ibm`ge;qty:100 200 150) /交易表t
ti sym qty
-----------------
10:01:01 msft 100
10:01:03 ibm 200
10:01:04 ge 150
q)show q:([] ti:10:01:00 10:01:01 10:01:01 10:01:02;sym:`ibm`msft`msft`ibm;px:100 99 101 98) /報價表q
ti sym px
-----------------
10:01:00 ibm 100
10:01:01 msft 99
10:01:01 msft 101
10:01:02 ibm 98
q)aj[`sym`ti;t;q]
ti sym qty px
---------------------
10:01:01 msft 100 101
10:01:03 ibm 200 98
10:01:04 ge 150

/aj[`sym`ti;t;q]的執行為:我們從t表中第一條記錄開始。尋找`msft與交易時間10:01:01(這時交易價格為100) 匹配的報價記錄,有兩個這樣的記錄,
/都標記為10:01:01,但最後一個記錄的價格為101,因此這時在這個時刻的最新報價就是101。接下來我們查找`ibm,但是我們發現截至10:01:03這個時刻,
/`ibm的最新報價在10:01:02 這個時間點,因此最新報價就是98。最後就是`ge在10:01:04 沒有匹配的報價記錄。

q)aj0[`sym`ti;t;q] /對於aj0,在時間上會選擇最新的報價時間,而不是交易時間,因此對於`ibm的最新報價時間是10:01:02,而不是交易時間10:01:03
ti sym qty px
---------------------
10:01:01 msft 100 101
10:01:02 ibm 200 98
10:01:04 ge 150
q)t:([] ti:10:01:01 10:01:03 10:01:04; sym:`msft`ibm`ge; qty:100 200 150; px:45 160 55)
q)t
ti sym qty px
---------------------
10:01:01 msft 100 45
10:01:03 ibm 200 160
10:01:04 ge 150 55
q)t asof `sym`ti!(`ibm;10:01:03) /我們也可以使用asof來直接查詢某個品牌在某個記錄的交易價格與報價,如果給定的是字典的形式,最後返回的結果也是字典,如果給定的是表的形式,最後返回的結果也是表
qty| 200
px | 160
q)t asof ([] sym:`msft`ibm; ti:10:01:01 10:01:03)
qty px
-------
100 45
200 160
q)promotions:([] name:`nuba`devi`nuba`devi`nuba;dt:2000.01.01 2005.02.14 2010.02.01 2012.08.12 2015.11.01;title:`associate`analyst`director`cfo`retired)
q)promotions
name dt title
-------------------------
nuba 2000.01.01 associate
devi 2005.02.14 analyst
nuba 2010.02.01 director
devi 2012.08.12 cfo
nuba 2015.11.01 retired
q)promotions asof `name`dt!(`nuba; 2009.07.04) /asof的還有一個重要用處就是,當給定的某個時間記錄,如果當前時間記錄沒有具體值,則會去匹配這個時間點之前的記錄值,
/這裡`nuba在2009.07.04的職位是associate
title| associate
q)promotions asof `name`dt!(`devi; 2015.12.01) /同樣`devi在2015.12.01之前的最新職位是cfo
title| cfo
q)events:([] name:`nuba`devi; dt: 2009.07.04 2015.12.01)
q)events
name dt
---------------
nuba 2009.07.04
devi 2015.12.01
q)aj[`name`dt; events; promotions] /我們也可以通過aj的形式來進行查詢操作
name dt title
-------------------------
nuba 2009.07.04 associate
devi 2015.12.01 cfo

8. 窗口聯接查詢(wj)

窗口連接查詢(wj)是對非等值聯接查詢(aj)的概括,特別適用於分析財務中交易和報價之間的關係。比如你想知道每筆交易的前後報價是多少。例如,

要確定一個交易的結果情況,則需要檢查交易時間內的買入價和賣出價的範圍。自己編寫這樣的查詢會很麻煩。所以Q提供了內置的窗口連接查詢(wj),可以計算每個交易周圍的間隔。

其查詢語法如下:

wj[w;c;t;(q;(f0;c0);(f1;c1))]

其中w是一個查詢範圍,例如交易的前10秒到交易後5秒;c是需要進行匹配的欄位名稱;t是交易表的名稱;(q;(f0;c0);(f1;c1))是對剩餘欄位的一個聚合等操作,如找最大的報價和最低的交易價格。

q)show t:([]sym:3#`aapl;time:09:30:01 09:30:04 09:30:08;price:100 103 101) /一個交易表t,交易表在時間上具有唯一性
sym time price
-------------------
aapl 09:30:01 100
aapl 09:30:04 103
aapl 09:30:08 101
q)show q:([] sym:8#`aapl;time:09:30:01+(til 5),7 8 9;ask:101 103 103 104 104 103 102 100;bid:98 99 102 103 103 100 100 99) /報價表q
sym time ask bid
---------------------
aapl 09:30:01 101 98
aapl 09:30:02 103 99
aapl 09:30:03 103 102
aapl 09:30:04 104 103
aapl 09:30:05 104 103
aapl 09:30:08 103 100
aapl 09:30:09 102 100
aapl 09:30:10 100 99
q)w:-2 1+:t `time /設置窗口寬度,這裡的含義是將t表的`time欄位的每個時間往前2秒,往後1秒,得到一個時間列表
q)w /得到的時間列表,我們需要豎著理解,如t表中09:30:01的推導時間是09:29:59和09:30:02
09:29:59 09:30:02 09:30:06
09:30:02 09:30:05 09:30:09
q)c:`sym`time /需要進行匹配的欄位
q)c
`sym`time
q)wj[w;c;t;(q;(::; `ask);(::; `bid))] /這裡沒有進行聚合操作,::的含義是將`ask和`bid欄位所有窗口時間內的記錄都選擇。對於窗口時間未完全匹配上的,就會像aj查詢操作一樣,
/去尋找當前時間點的之前的最新的記錄,如09:30:08 101的窗口時間是09:30:06和09:30:09,而沒有09:30:06這條時間記錄,因此就會去匹配09:30:06之前的最新記錄09:30:05的數據
sym time price ask bid
--------------------------------------------------
aapl 09:30:01 100 101 103 98 99
aapl 09:30:04 103 103 103 104 104 99 102 103 103
aapl 09:30:08 101 104 103 102 103 100 100
q)wj[w;c;t;(q;(max; `ask);(min; `bid))] /這裡我們對q表匹配後的數據進行了聚合操作,如返回窗口時間內的`ask欄位的最大值和`bid欄位的最小值
sym time price ask bid
---------------------------
aapl 09:30:01 100 103 98
aapl 09:30:04 103 104 99
aapl 09:30:08 101 104 100
q)wj1[w; c; t; (q; (::; `ask); (::; `bid))] /wj1的窗口匹配機制與wj的匹配機智有一些不同,wj1隻會匹配窗口時間內的,對於窗口時間未完全匹配上的,會去尋找當前時間點內的記錄,
/如09:30:08 101的窗口時間是09:30:06和09:30:09,而沒有09:30:06這條時間記錄,因此就會去匹配09:30:06內的最新記錄09:30:08的數據
sym time price ask bid
--------------------------------------------------
aapl 09:30:01 100 101 103 98 99
aapl 09:30:04 103 103 103 104 104 99 102 103 103
aapl 09:30:08 101 103 102 100 100

四、 表的參數化查詢

關係型資料庫具有存儲過程,這些過程是包含SQL語句的資料庫語言。而編程語言不是SQL標準的一部分。而且不同語言之間存在顯著差異,但通常是第三代命令式編程語言。

這種情況迫使程序員做出選擇:學習專有語言以將某些功能放在數據上,或者將數據提取到應用程序伺服器中以執行計算。各種多層體系結構已經發展到解決這個問題,但它們會增加系統成本和複雜性。

這種分離在kdb +中被消除,因為Q是存儲過程語言,並且它具有處理大數據的能力和性能。在表上運行的任何Q函數實際上都是存儲過程。函數參數可用於為查詢提供特定值。

特別是,可以在具有參數的函數內調用select,exec,update和delete模板,以生成參數化查詢。

q)t:([] c1:`a`b`c; c2:10 20 30; c3:1.1 2.2 3.3)
q)select from t where c2>15 /使用標準select語句查詢
c1 c2 c3
---------
b 20 2.2
c 30 3.3
q)proc:{[sc] select from t where c2>sc} /我們可以將select標準查詢語句放在函數當中,後續相同的查詢操作我們只需要傳遞參數即可
q)proc 15 /函數的參數化查詢
c1 c2 c3
---------
b 20 2.2
c 30 3.3
q)proc1:{[nms;sc] select from t where c1 in nms, c2>15} /函數化複雜的select條件查詢
q)proc1[`a`c;15] /函數式查詢
c1 c2 c3
---------
c 30 3.3
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)proc2:{[t;nms;delta] update c2+delta from t where c1 in nms} /我們傳遞的參數也可以是針對不同的表
q)proc2[t;`a`c;100]
c1 c2 c3
----------
a 110 1.1
b 20 2.2
c 130 3.3
q)t
c1 c2 c3
---------
a 10 1.1
b 20 2.2
c 30 3.3
q)proc2[`t;`a`c;100] /同樣需要改變原始表格的數據,我們也是需要傳遞表名的形式(`table_name)
`t
q)t
c1 c2 c3
----------
a 110 1.1
b 20 2.2
c 130 3.3
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)procf:{[cs] cs#t} /多欄位的查詢方式
q)procf[`c1`c2]
c1 c2
-----
a 10
b 20
c 30

五、 視圖

SQL視圖實際上是一個查詢表達式,其結果集可以像表一樣使用。視圖對於封裝數據非常有用,例如隱藏列或簡化複雜查詢。

Q-sql 視圖是使用雙冒號運算符創建的別名的命名表表達式。在視圖中使用模板很常見。

q)t:([] c1:`a`b`c; c2:10 20 30)
q)t
c1 c2
-----
a 10
b 20
c 30
q)u:select from t where c2>15 /將查詢語句賦給一個變數
q)v::select from t where c2>15 /創建一個視圖
q)u
c1 c2
-----
b 20
c 30
q)v
c1 c2
-----
b 20
c 30
q)view `v /查看視圖的內容
"select from t where c2>15"
q)update c2:15 from `t where c1=`b /更新表的內容
`t
q)u /這時我們發現通過變數u查詢,並沒有得到更新的內容
c1 c2
-----
b 20
c 30
q)v /視圖的方式查詢能夠同步得到更新的內容
c1 c2
-----
c 30
q)a:42
q)b::a /這樣實際上是前面講的別名,a的值改變會同步到b的值也改變
q)views `. /查詢當前內存中有哪些視圖(或別名)
`b`v

六、 函數式查詢

我們知道Q語言是一種高度抽象的概括語言,與其他編程語言的風格非常不同,同時該編程語言的語句信息密度非常的大,因此學起來有一定的難度,但是當你掌握之後,你會發現它是如此的優美與簡潔。

前面介紹的表的增刪改查,Q語言還可以通過更加簡潔的形式來查詢,那就是函數式查詢,其查詢的語法模板如下:

?[t;c;b;a] / select 與 exec查詢操作方式

![t;c;b;a] / update 與 delete查詢操作方式

傳遞的參數不同,最後查詢的結果可能就不同,通過重載的形式來進行處理,這裡t、c、b、a的含義分別是:

t——>table_name

c——>查詢的限制條件,相當於whereb——>分組的限制條件,0b一般表示沒有分組,相當於bya——>聚合類的函數,()空列表表示沒有限制條件或聚合操作

q)t:([] c1:`a`b`a`c`a`b`c; c2:10*1+til 7; c3:1.1*1+til 7)
q)ft:{([] c1:`a`b`a`c`a`b`c; c2:10*1+til 7; c3:1.1*1+til 7)} /ft為函數,內容為創建一個表

1. select查詢

q)t
c1 c2 c3
---------
a 10 1.1
b 20 2.2
a 30 3.3
c 40 4.4
a 50 5.5
b 60 6.6
c 70 7.7
q)ft
{([] c1:`a`b`a`c`a`b`c; c2:10*1+til 7; c3:1.1*1+til 7)}
q)select from t
c1 c2 c3
---------
a 10 1.1
b 20 2.2
a 30 3.3
c 40 4.4
a 50 5.5
b 60 6.6
c 70 7.7
q)?[t; (); 0b; ()] /該查詢操作與select from t的查詢操作是一樣的,這裡c為空列表,b為0b表示沒有分組,a為空列表表示沒有聚合操作
c1 c2 c3
---------
a 10 1.1
b 20 2.2
a 30 3.3
c 40 4.4
a 50 5.5
b 60 6.6
c 70 7.7
q)?[`t; (); 0b; ()] /傳遞表時,通過傳遞`table_name的形式在原始表上進行相應的操作
c1 c2 c3
---------
a 10 1.1
b 20 2.2
a 30 3.3
c 40 4.4
a 50 5.5
b 60 6.6
c 70 7.7
q)?[ft[]; (); 0b; ()] ] /傳遞表時我們也可以傳遞函數表
c1 c2 c3
---------
a 10 1.1
b 20 2.2
a 30 3.3
c 40 4.4
a 50 5.5
b 60 6.6
c 70 7.7
q)select from t where c2>35, c1 in `b`c
c1 c2 c3
---------
c 40 4.4
b 60 6.6
c 70 7.7
q)?[t; ((>; `c2; 35); (in; `c1; enlist `b`c)); 0b; ()] /這裡的查詢操作與select from t where c2>35, c1 in `b`c是一樣的,在c中,對於多個限制條件,
/我們將每一個限制條件單獨寫成前綴的形式(>; `c2; 35),最後將多個限制條件組合成一個列表
c1 c2 c3
---------
c 40 4.4
b 60 6.6
c 70 7.7
q)select max c2, c2 wavg c3 from t
c2 c3
------
70 5.5
q)?[t; (); 0b; `maxc2`wtavg!((max; `c2); (wavg; `c2;`c3))] /這裡的查詢操作與select max c2, c2 wavg c3 from t是一樣的,在a中,我們需要將聚合函數寫成字典的形式,
/每一個聚合操作為一個字典的值,字典的key不限制,但是盡量不要與表的欄位名相同
maxc2 wtavg
-----------
70 5.5
q)select by c1 from t
c1| c2 c3
--| ------
a | 50 5.5
b | 60 6.6
c | 70 7.7
q)?[t; (); (enlist `c1)!enlist `c1; ()] /這裡的查詢操作與select by c1 from t是一樣的,這裡添加了分組查詢,因此b不再是0b了,分組查詢也是一樣,我們需要將分的組寫成字典的形式,
/對於單個分組的欄位,注意使用enlist
c1| c2 c3
--| ------
a | 50 5.5
b | 60 6.6
c | 70 7.7
q)?[t; (); `c1`c2!(`c1;`c2); ()] /多個分組的欄位查詢操作
c1 c2| c3
-----| ---
a 10| 1.1
a 30| 3.3
a 50| 5.5
b 20| 2.2
b 60| 6.6
c 40| 4.4
c 70| 7.7
q)select max c2, c2 wavg c3 by c1 from t where c2>35, c1 in `b`c
c1| c2 c3
--| ------
b | 60 6.6
c | 70 6.5
q)c:((>; `c2; 35); (in; `c1; enlist `b`c)) /where子句,多個限制條件用前綴形式,並組合成列表
q)b:(enlist `c1)!enlist `c1 /分組子句,寫成字典的形式
q)a:`maxc2`wtavg!((max; `c2); (wavg; `c2; `c3)) /聚合函數,也是用前綴形式,最後寫成字典的形式
q)?[t;c;b;a]
c1| maxc2 wtavg
--| -----------
b | 60 6.6
c | 70 6.5
q)t:([] c1:`a`b`c`a; c2:10 20 30 40)
q)t
c1 c2
-----
a 10
b 20
c 30
a 40
q)select[>c1] c1,c2 from t /select查詢的排序
c1 c2
-----
c 30
b 20
a 10
a 40
q)?[t; (); 0b; `c1`c2!`c1`c2; 0W; (>:; `c1)] /函數查詢的一種擴展形式,多了兩個參數,第一個參數是後面的排序操作的用來比較大小的初始值,我們選擇0W,第二個為列表,表示將整個c1欄位進行排序
c1 c2
-----
c 30
b 20
a 10
a 40

2. exec查詢

exec查詢操作與select查詢操作基本相似,只是當沒有分組時b的參數不再是0b,而是一個空列表(),同時返回的結果取決於傳遞的參數形式,如果為列表形式返回結果為列表,

如果為字典的形式,返回結果就是字典

q)t:([] c1:`a`b`c`a; c2:10 20 30 40; c3:1.1 2.2 3.3 4.4)
q)t
c1 c2 c3
---------
a 10 1.1
b 20 2.2
c 30 3.3
a 40 4.4
q)exec distinct c1 from t
`a`b`c
q)?[t; (); (); (distinct; `c1)] /這裡的a參數為列表的形式,因此返回的結果是一個列表
`a`b`c
q)exec c1:distinct c1 from t
c1| a b c
q)?[t; (); (); (enlist `c1)!enlist (distinct; `c1)] /這裡的a參數為字典的形式,因此返回的結果是一個字典
c1| a b c
q)exec distinct c1,c2 from t
c1| `a`b`c
c2| 10 20 30 40
q)?[t; (); (); `c1`c2!((distinct; `c1); `c2)] /這裡的a參數為字典的形式,因此返回的結果是一個字典
c1| `a`b`c
c2| 10 20 30 40
q)exec c2 by c1 from t
a| 10 40
b| ,20
c| ,30
q)t
c1 c2 c3
---------
a 10 1.1
b 20 2.2
c 30 3.3
a 40 4.4
q)?[t; (); `c1; `c2] /對單個欄位進行分組的查詢操作形式
a| 10 40
b| ,20
c| ,30

3. update查詢

update查詢操作形式與前面介紹的select有一點差別,同時?被!取代。

q)t:([] c1:`a`b`c`a`b; c2:10 20 30 40 50)
q)t
c1 c2
-----
a 10
b 20
c 30
a 40
b 50
q)update c2:100 from t where c1=`a
c1 c2
------
a 100
b 20
c 30
a 100
b 50
q)c:enlist (=; `c1; enlist `a) /這裡的c為修改的限制條件,一樣用前綴的形式,同時注意對於單個限制條件要寫成enlist的形式
q)b:0b /0b表示不進行分組
q)a:(enlist `c2)!enlist 100 /a為要update的值
q)![t;c;b;a]
c1 c2
------
a 100
b 20
c 30
a 100
b 50
q)update c2:sums c2 by c1 from t
c1 c2
-----
a 10
b 20
c 30
a 50
b 70
q)c:()
q)b:(enlist `c1)! enlist `c1 /這裡對c1欄位進行分組,然後累加分組後的c2欄位的值
q)a:(enlist `c2)! enlist(sums; `c2) /累加操作
q)c
q)b
c1| c1
q)a
c2| + `c2
q)![t; c; b; a]
c1 c2
-----
a 10
b 20
c 30
a 50
b 70

4. delete查詢

delete操作也是與前面類似,但是這裡需要注意的是c和a參數是至少要有兩者中的一個,如果c存在,則指定要刪除的行;如果a存在,則它是要刪除的欄位名稱。

在c存在的情況下,必須指定a為空符號列表。同時b的參數始終為0b,因為沒有分組刪除。

q)t:([] c1:`a`b`c`a`b; c2:10 20 30 40 50)
q)t
c1 c2
-----
a 10
b 20
c 30
a 40
b 50
q)delete from t where c1=`b
c1 c2
-----
a 10
c 30
a 40
q)![t; enlist (=; `c1; enlist `b); 0b; `symbol$()] /c為限制條件,同時a要將列錶轉換為symbol形式
c1 c2
-----
a 10
c 30
a 40
q)delete c2 from t
c1
--
a
b
c
a
b
q)![t; (); 0b; enlist `c2] /c不存在,a的參數為指定刪除的欄位名稱
c1
--
a
b
c
a
b

推薦閱讀:

相关文章