Short answer:

A table is a reference to a (column) dictionary.


The internal representation of a table is nearly identical to that of a dictionary. We can use the flip command to create a table from a dictionary:

q)t: ([] a: 1 2 3; b: 4 5 6; c: 7 8 9)
q)d: `a`b`c ! (1 2 3; 4 5 6; 7 8 9)
q)t ~ flip d
1b
q)

In fact, when a dictionary is flip‘ed, the underlying core data structure remains untouched. The table itself is a simple, small object that refers to the original dictionary. Using .Q.w, we can measure how much more memory a table takes than the corresponding dictionary:

q).Q.w[]`used         // memory usage baseline
112992j
q)x:`a`b`c!3 3#til 9  // create a small dictionary
q).Q.w[]`used
113424j
q)x:flip x
q).Q.w[]`used         // memory usage delta is
113456j               // just 32 more bytes
q)

No matter how large the underlying dictionary is, creating a table is fast and still takes only 32 bytes:

q)x:`a`b`c!3 100000#til 10
q).Q.w[]`used
1686192j
q)x:flip x
q).Q.w[]`used
1686224j          // 32 = 1686224 - 1686192
q)

Now, Let’s examine how a keyed table is related to a dictionary. We start by creating a simple keyed table:

q)t: ([] a: 1 2 3; b: 4 5 6; c: 7 8 9)
q)keyedTable: `a`b xkey t
q)keyedTable
a b| c
---| -
1 4| 7
2 5| 8
3 6| 9
q)keys keyedTable
`a`b
q)

Since keyedTable is a table, one might expect it to have the same type as t but instead, q presents the following surprise:

q)type t
98h                  // type table as expected
q)type keyedTable
99h                  // *NOT* 98h
q)

Type 99h is the type number for dictionaries. If keyedTable really is a dictionary, we should be able to extract its key and value:

q)key keyedTable
a b
---
1 4
2 5
3 6
q)value keyedTable
c
-
7
8
9
q)

Indeed, keyedTable is a dictionary – one that holds unkeyed tables for both its key and its value:

q)type key keyedTable
98h
q)type value keyedTable
98h
q)

This suggests that we can create a keyed table by using the ! (dict) operator with two unkeyed tables:

q)(key keyedTable)!(value keyedTable)
a b| c
---| -
1 4| 7
2 5| 8
3 6| 9
q)

Lastly, joining the two flipped tables brings us back to the original dict.

q)(flip key keyedTable),(flip value keyedTable)
a| 1 2 3
b| 4 5 6
c| 7 8 9
q)

For more information, see Creating dictionaries and tables from C.

xasc and xdesc. Consider the following table:

q)table: ([] x: 10 ? "abc"; y: 10 ? til 10)
q)table
x y
---
a 7
a 7
b 1
b 9
a 1
a 0
c 8
b 8
c 3
c 1
q)

To sort by column x, instead of “ORDER BY x”, we write `x xasc table:

q)`x xasc table // sort by column x
x y
---
a 7
a 7
a 1
a 0
b 1
b 9
b 8
c 8
c 3
c 1
q)

The application of xdesc is similar.

In addition, to sort by multiple columns, instead of “ORDER BY y, x” or “ORDER BY y, x DESC, we pass the list of column names as the left argument to xasc or xdesc, respectively. For example,

q)`y`x xdesc select from table where y > 5
x y
---
b 9
c 8
b 8
a 7
a 7
q)

Don’t confuse xasc and xdesc with asc and desc, which operate on a vector instead of a table. Read more about sorting vectors in this related faq.

Modify the file .d in the splayed table directory. The contents are editable via operators get and set.

$ rlwrap q sp.q
KDB+ 2.7 2011.02.16 Copyright © 1993-2011 Kx Systems
+`p`city!(`p$`p1`p2`p3`p4`p5`p6`p1`p2;`london`london`london..
(+(,`color)!,`blue`green`red)!+(,`qty)!,900 1000 1200
+`s`p`qty!(`s$`s1`s1`s1`s2`s3`s4;`p$`p1`p4`p6`p2`p2`p4;300 ..
q)sp
s p qty
———
s1 p1 300
s1 p2 200
s1 p3 400
q)`:splaydir/ set sp
`:splaydir/
q)\ls -a splaydir
,”.”
“..”
“.d” // this is where the col names live
,”p”
“qty”
,”s”
q)get `:splaydir/.d
`s`p`qty
q)`:splaydir/.d set reverse get `:splaydir/.d
`:splaydir/.d
q)get `:splaydir/.d
`qty`p`s
q)

Verify with a fresh kdb instance:

$ rlwrap q splaydir
KDB+ 2.7 2011.02.16 Copyright © 1993-2011 Kx Systems
q)\v
,`splaydir
q)splaydir
qty p s
——-
300 0 0
200 1 0
400 2 0
q)

See also: xcol and xcols faq