Kdb+ 建表与相关概念介绍

本文介绍了Kdb+数据库的建表语法,包括字典与表的概念,建表语句,主键与外键的设置。强调了Kdb+中字典的顺序性和表的二维结构。同时,探讨了Kdb+写数据与查询数据的基本操作,并吐槽了Q语言的一些难点,如操作符重载。最后,提到了一些基础语法速记,帮助读者更好地理解和使用Kdb+。
摘要由CSDN通过智能技术生成

这个数据库似乎比较流行,但其操作方法 Q 又与 SQL 截然不同。虽然中文互联网有教程,但居然是收费的。虽然可以访问官方直接查询其文档,但他们这个文档写的也非常糟糕,读着头疼。因此,我将自己整理过程的部分片段分享出来,希望能给读者节约时间。
参考地址先列出:
关于 table 概念基本介绍:https://code.kx.com/q4m3/8_Tables/#8411-extracting-column-data
关于枚举 enumeration:https://code.kx.com/q4m3/7_Transforming_Data/#75-enumerations
与枚举相关的操作符:https://code.kx.com/q/ref/enum-extend/
关于 sym file:https://code.kx.com/q/wp/symfiles/#symbols-vs-strings
关于表的持久化:https://code.kx.com/q4m3/14_Introduction_to_Kdb%2B/#1412-foreign-keys-and-link-columns
关于 linking column:https://code.kx.com/q/kb/linking-columns/

分割线下是正文


1 Kdb

1.1 建表与相关语法

1.1.1 字典与表

一般来说,讨论表首先要认识建表语句。但在Kdb+中,讨论表table前需要先了解什么是字典dictionary。

字典应该看作一种值到域的映射,逻辑上与一个KV结构相同,但物理上存储为键值对列表。定义时使用叹号连接键值,发音为bang。出于历史原因,字典本身没有唯一性约束,但访问数据时只有第一个写入的键值对能被访问。
可以使用````u# ```来强调具有唯一约束的字典键,通过实现哈希结构提高效率
字典中的元组之间是有顺序关系的。
可以创建空字典,可以使用$指定键值类型。

(`symbol$())!`float$()

访问字典的语法,类似于访问列表,都需要使用中括号[],括号中的参数是键。

1.1.2 建表语法

(译者注:如果认为字典是一维结构,通过键可以访问值,那么表可以看作一个“二维”结构,即需要列名与行号才能访问值,如果仅提供列名或行号,则只能访问到一个列表)
表可以看作某种字典的“翻转(flip)”,用表的内容描述这个字典就是:键是列名,值是该列所有值。而翻转主要体现在查询过程中。前面提到,表是二维结构,访问值需要提供两个参数。对于翻转前的字典,通过将第一个参数声明为列名,可以获取该列所有值,而对于表,则需要将第二个值声明为列名以获取同样结果。获取表的过程中,第一个参数确定了行号。即:

t[<row_num>;<col_name>]
d[`name;]  // 转置前的字典获取列所有值,分号后是第二个参数,此处为空 
t[;`name]  // 翻转后的表,获取结果同上

建表语法中,中括号[]用于声明主键。需要注意的是,如果使用如下语句建表,列名是不需要强调symbol类型的。

t: ([] *c1*:*L1*; ...; *cn*:*Ln*)

Kdb+会自作聪明地、将具有同样键名的单元素字典列表转化为表。直观地讲,就是认为如下内容会是表。如下内容中,本身将t定义为列表,但列表的每个元素都是一个字典,每个字典都只有一个元素且键名相同,因此t被转化为表。

t: (`name`iq!(`Dent;98); `name`iq!(`Beeblebrox;42))

1.1.3 主键与外键

为简便,将keyed table称为主键表。Kdb+将主键认为是与原表相关的另一个表,两个表通过元组顺序的位置关联。基本定义语法例子参考如下。实际文档中还提供了一种“更基础”的做法,是将两个表通过“!”链接起来,过于复杂,此处略去。

kt:([eid:1001 1002 1003] name:`Dent`Beeblebrox`Prefect; iq:98 42 126)

定义主键还有一个更简单方式,即使用xkey关键字。如果对于表t1本身已有列kcol,则定义其为主键的语法如下。如果取消其主键,则使用()定义其主键。

t1: `kcol xkey t1

这里的主键是有约束能力的,重复主键值的元组无法写入表。但要说明的是,可能由于Kdb+“过于宽松”的完整性约束,向一个主键表写入重复主键值非常容易,例如可以定义另一个表kt2是kt无主键的情况,向kt2写入数据不受主键约束,且数据可反映在kt中。

kt2: () xkey kt

对于主键表,可以直接将主键列值作为唯一参数,通过中括号访问。注意,主键表和表属于不同的类型,表的访问方法(2个参数)并不能用于访问主键表。

设置外键重载了$符号,如下:

<table>:([]<col>:<ref_col>$())
trade: ([] sym:`financials$()) // 具体例子

注意到,设置外键的语法中,实际是把被引用表(列)作为一种“数据类型”,让引用列存储数据类型的索引

1.2 写数据与查数据

建表、写与查才能验证我们真成功实现了预期。
写数据命令在文档中的表达也非常奇怪。以下两种方法都能写入数据,但文档中却是放在同一行,容易误解为一个命令中包含两个部分。其中,x必须是symbol类型,y是符合表结构的列。

x insert y
insert[x;y]

查数据相对简单,直接使用变量名后接中括号,中括号内使用查询参数即可。

1.3 吐槽

作为一个DSL,Q对操作符实现了重载,这可能是导致该语言难以理解应用的原因之一。例如在下述代码中,操作符“?”就有两种含义,分别是以生成指定数量的随机数组,以及查找数组位置。

q)u:`g`aapl`msft`ibm
q)v:1000000?u
q)k:u?v

这门语言的文档中开口闭口都要“After a bit of Zen”,但真正的Zen是蕴藏在符号之下的,而不是通过一些看似极简实而晦涩的语法体现。

1.4 一些基础语法速记

如果进一步阅读原文文档,会发现有些操作符的用法非常违背直觉,这里简单列两个。

在某些函数调用中,需要用变量名的symbol格式,而有些地方可以直接用变量名。下文用<ref_x>表达需要用反引号的symbol格式,<x>表达不需要。

// 给列表添加元素:
<lst>,:<elem>
// 给定两个列表,一个不重复列,一个目标列,求枚举,即索引编码:
<ref_unique_lst>$<src_lst>
// 给定两个列表,对源列表去重并将结果补充到不重复列表中:
<ref_unique_lst>?<src_lst>

声明链接列linking column重载了操作符!,如下:

update parent:`t!id?101 101 102 102 from `t

parent是新增的链接列,t是被链接的表,也是新增列的表,id是链接目标。理解这一点,本质要理解这个表达式:id?101 101 102 102。该表达式就是从按照列举字面量(101 101 102 102),从id列表中取得索引。而前面的\`t! 则是将这个索引列表与t联系起来,如果没有这一步,那么索引结果就不能用来访问t中的列与值。例如,上述增加的列可以略作修改如下,此时产生的列nparent就不能能问表t,但从结果值上讲与parent列是一样的。

update nparent:`id?101 101 102 102 from `t

类似地,建表时,直接指定某列为某个表的索引:

t2:([] c3:`sym?`a`b`a`c; c4: 1 2 3 4.)

其中,sym可以是存在或不存在的列表,该语句让t2表的c3列实际存储了写出的symbol类型字面量在列表sym中的索引。注意,在这里,问号?虽然被重载,但实际表达了查找与补充(extend)的含义,即查找字面量在目标函数中的索引。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值