A q programozási nyelv

Adatbázis-kezelés

A q a kdb+ nevű adatbázis-kezelő rendszer nyelve, ezért lehetőséget ad a magas szintű adatbázis-műveletek megadására. Ezek tulajdonképpen mind szintaktikus cukorkák, mivel a táblák csak speciális formájú szótárak, kezelhetnénk őket a szótár- és listaműveletekkel is.

q-sql

A q-sql a hagyományos adatbázis-kezelő rendszerek SQL-jéhez hasonló lekérdezőnyelv. Teljesen integrálva van a q-val, így a kifejezések tartalmazhatnak q függvényeket, egy q függvény visszaadhatja egy lekérdezés eredményét stb.

select

Az SQL-hez hasonlóan a q-sql-ben is az alapvető művelet a select. Egy select kifejezés az alábbi részekből épülhet fel:

select [distinct] mezők [by mezők] from tábla [where megszorítások]

A legegyszerűbb formában minden opcionális elemet elhagyunk:

select from 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

A select kulcsszó után felsorolhatjuk azokat a mezőket, amelyeket meg akarunk kapni. Vigyázzunk, mert ekkor a kulcsmezők már nem lesznek kulcsok:

select s, name, city from s s name city --------------- s1 smith london s2 jones paris s3 blake paris s4 clark london s5 adams athens

Az SQL-hez hasonlóan használhatjuk a distinct kulcsszót a duplikátumok kiszűrésére. Ez egyébként a q-ban listafüggvényként is megtalálható, viszont speciális jelentése van, ha közvetlenül a select után írjuk, és nem zárójelezzük egybe a mezőnevekkel.

select distinct status, city from s status city ------------- 20 london 10 paris 30 paris 30 athens

A where kulcsszóval szűrőfeltételeket adhatunk meg. Több feltételt vesszővel választhatunk el, ezért ha a konkatenáció operátort is szeretnénk használni, be kell zárójeleznünk a kifejezést.

select from s where status>=20 s | name status city --| ------------------- s1| smith 20 london s3| blake 30 paris s4| clark 20 london s5| adams 30 athens

Lekérdezések során a tábla kiegészül egy rejtett i nevű mezővel, amely a sorszámokat tartalmazza. Ezt is belevehetjük az eredménybe, és akár kifejezésekben is felhasználhatjuk.

select i,name from s where 1=i mod 2 x name ------- 1 jones 3 clark

A where kifejezésben az oszlopnevek az egész oszlopra mint listára vonatkoznak, nem az egyes elemekre, mint az SQL-ben. Azonban a q atomi műveleteinek köszönhetően a legtöbb feltétel leírható az SQL-ben megszokott módon. Pl. a "status<=20" kifejezésben a "=<" operátor egy listát és egy atomot kap paraméterül, ezért a lista minden egyes elemére végrehajtódik. Az eredmény egy boolean lista, ahol pontosan azok az elemek lesznek 1b (true) értékek, ahol a status oszlopban 20-nál nagyobb vagy egyenlő érték található. A where feltétel ez alapján szűri a sorokat. Célszerű azokat a feltételeket rakni elsőnek, amelyek a legtöbb sort fogják kidobni az eredményből.

A mezőlistában megadhatunk számított mezőket is. Ezekben a kifejezésekben a mezőnevek szintén az egész oszlopot jelölik. A "többi mező" jelölésére szolgáló csillag azonban nem szerepel a q-ban. Ha csak bővíteni szeretnénk a táblát, használjuk az update műveletet.

select name, st:status*2 from s name st -------- smith 40 jones 20 blake 60 clark 40 adams 60

A by kulcsszó után megadhatunk mezőket, amelyek alapján a sorokat csoportosítani akarjuk. A csoportosító mezők az eredményben kulcsok lesznek.

select by city from s city | s name status ------| --------------- athens| s5 adams 30 london| s4 clark 20 paris | s3 blake 30 select s,name,status by city from s city | s name status ------| -------------------------- athens| ,`s5 ,`adams ,30 london| `s1`s4 `smith`clark 20 20 paris | `s2`s3 `jones`blake 10 30

SQL-ben van egy olyan korlátozás, hogy a GROUP BY-ban nem előforduló mezők nem szerepelhetnek az eredményben, kivéve ha valamilyen aggregáló függvényt alkalmazunk rájuk. Ez a korlátozás a q-ban nincs benne, és érdekes anomáliákat tapasztalhatunk, ha kihasználjuk ezt a hiányt. Ha nem sorolunk fel a select után mezőket, akkor az egyes csoportokból csak az utolsó sor marad meg, ha viszont felsoroljuk a mezőket, akkor egy csoporthoz csak egy sor fog tartozni, ahol a nem csoportosító mezőkből lista keletkezik. A helyes eredményt az "ungroup" függvény alkalmazásával kapjuk meg, de természetesen az SQL-hez hasonlóan az egyes mezőket is aggregálhatjuk az arra szolgáló függvényekkel (pl. first, last, min, max, avg, sum).

select s,name,sum status by city from s city | s name status ------| -------------------------- athens| ,`s5 ,`adams 30 london| `s1`s4 `smith`clark 40 paris | `s2`s3 `jones`blake 40 ungroup select s,name,sum status by city from s city s name status ---------------------- athens s5 adams 30 london s1 smith 40 london s4 clark 40 paris s2 jones 40 paris s3 blake 40

exec

Az exec utasítás szintaxisa és szemantikája szinte teljesen megegyezik a select-ével, a különbség az eredmény típusában van. A select mindig táblát ad vissza. Az exec egy listát ad vissza, ha az eredmény egy oszlop, és egy listákból álló szótárat, ha az eredmény több oszlop.

exec name from s `smith`jones`blake`clark`adams exec s,name from s s | s1 s2 s3 s4 s5 name| smith jones blake clark adams

update

Az update utasítás hasonlít a select-hez, a különbség az, hogy kiválasztások helyett módosításokat kell felsorolni. A művelet érintetlenül hagyja a nem módosított oszlopokat, és azokat a sorokat, amelyekre a where feltétel (ha van) hamis értéket ad vissza.

update i from s s | name status city x --| --------------------- s1| smith 20 london 0 s2| jones 10 paris 1 s3| blake 30 paris 2 s4| clark 20 london 3 s5| adams 30 athens 4 update status:5 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 s5| adams 5 athens

delete

Az SQL-lel ellentétben a q delete utasítása oszlopot is tud törölni a táblából. Sorokat is törölhetünk, ha where feltétellel megadjuk a törlendő sorok tulajdonságait. Viszont a kettő egyszerre nem működik.

delete city from s s | name status --| ------------ s1| smith 20 s2| jones 10 s3| blake 30 s4| clark 20 s5| adams 30 delete from s where status=20 s | name status city --| ------------------- s2| jones 10 paris s3| blake 30 paris s5| adams 30 athens delete status from s where status=20 'nyi

Helyben módosítás

Az update és delete műveletek nem módosítják a táblát, csak visszaadnak egy új táblát, amelyben már benne van a módosítás eredménye. Lehetőség van a helyben módosításra is, ha a tábla nevét szimbólumként adjuk át.

delete city from p; p | name color weight --| ------------------ p1| nut red 12 p2| bolt green 17 p3| screw blue 17 p4| screw red 14 p5| cam blue 12 p6| cog red 19 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 delete city from `p; `p p p | name color weight --| ------------------ p1| nut red 12 p2| bolt green 17 p3| screw blue 17 p4| screw red 14 p5| cam blue 12 p6| cog red 19

Összekapcsolások

Az SQL-hez hasonlóan a q is lehetőséget ad táblák összekapcsolására.

Idegen kulcsos összekapcsolás

Egy mezőt úgy tehetünk idegen kulccsá, hogy típusként megadjuk neki a hivatkozott tábla nevét. Ekkor a mező értékei csak a hivatkozott tábla kulcsának értékeit vehetik fel.

pp:([a:1 2 3 4 5] b:"almad") qq:([] fo:`pp$1 4 3 2 3 5 8) 'cast qq:([] fo:`pp$1 4 3 2 3 5)

Az idegen kulcsok megjelennek a tábla metaadatai között is.

meta qq c | t f a --| ------ fo| i pp

SQL-ben az összekapcsoláshoz általában explicit ki kell írnunk a feltételeket. q-ban az idegen kulcsos összekapcsolás automatikus. Ha a select kifejezésben a tábla idegen kulcsot tartalmaz, a kapcsolt tábla mezői elérhetőek, ha az idegenkulcs-mező nevével prefixáljuk őket.

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 select s, s.name, p.name, qty from sp s name name1 qty ------------------ s1 smith nut 300 s1 smith bolt 200 s1 smith screw 400 s1 smith screw 200 s4 clark cam 100 s1 smith cog 100 s2 jones nut 300 s2 jones bolt 400 s3 blake bolt 200 s4 clark bolt 200 s4 clark screw 300 s1 smith cam 400

Idősoros összekapcsolás

Az idősoros adatok kezelése a kdb+ egyik legnagyobb erőssége. Például egy táblában tárolhatjuk néhány részvény árát bizonyos időpontokban. Azt feltételezzük, hogy a részvény ára konstans, ha nem érkezik rá új ár:

stock:([]name:`AAPL`AAPL`GOOG`MSFT`FB`MSFT`GOOG; date:2012.01.01 2012.02.01 2012.02.01 2012.02.01 2012.03.01 2012.03.01 2012.03.01;val:100 200 500 300 100000 400 600) stock name date val ---------------------- AAPL 2012.01.01 100 AAPL 2012.02.01 200 GOOG 2012.02.01 500 MSFT 2012.02.01 300 FB 2012.03.01 100000 MSFT 2012.03.01 400 GOOG 2012.03.01 600

Például a fenti adatok alapján az `AAPL részvény értéke 2012. januárban végig 100, február 1-től pedig 200. Az idősoros összekapcsolás (asof join) pontosan ezt fejezi ki. Az első paraméter egy tábla, amelynek van egy dátum/idő oszlopa. A második paraméter lehet egy szótár vagy egy tábla, amely hivatkozik a tábla egy oszlopára és az időre. Az eredmény megadja, milyen érték tartozik a megadott elemhez az adott időpontban.

stock asof `name`date!(`AAPL;2012.01.15) val| 100 stock asof `name`date!(`AAPL;2012.02.15) val| 200

Táblák tárolása

A tábla lemezen való tárolása fontos feladat, mivel az adatbázis-kezelő processz összeomlása után is szeretnénk megtartani az adatainkat.

Splay-elés

Nagyobb tábláknál hasznos az a módszer, hogy minden oszlopot külön fájlban tárolunk. Ezt a műveletet a q nyelv natívan támogatja. Használatához egyszerűen egy könyvtárnevet kell megadnunk a végén / jellel (szemben a szokásos mentéssel, amikor ez a jel hiányzik).

t:([] c1:101 102 103; c2:1.1 2.2 3.3) `:c:/q/data/t.dat/ set t `:c:/q/data/t.dat/

Sajnos csak kulcs nélküli és nem enumerálható szimbólumot nem tartalmazó táblát lehet ilyen módon kimenteni. A szimbólumokra vonatkozó megszorítás elég kemény. A legkönnyebb megoldás, ha a .Q.en függvénnyel enumeráljuk a szimbólumokat, ezáltal létrejön egy "sym" nevű fájl, amely tartalmazza az összes szimbólumot.

`:stock/ set stock 'type bstock:.Q.en[`:stock;stock] meta bstock `sym$`AAPL`AAPL`GOOG`MSFT`FB`MSFT`GOOG `:stock/ set stock `:stock/ -1 value "\\dir stock"; A meghajtóban (D) lévő kötet DATA. A kötet sorozatszáma: 54E7-3141 D:\utility\q\stock tartalma: 2012.05.12. 20:13 <DIR> . 2012.05.12. 20:13 <DIR> .. 2012.05.12. 20:13 22 .d 2012.05.12. 20:13 44 date 2012.05.12. 20:13 44 name 2012.05.12. 20:08 26 sym 2012.05.12. 20:13 44 val 5 fájl 180 bájt 2 könyvtár 170 629 476 352 bájt szabad