在序表的主键中,除了可以使用普通的主键,还可以使用一种特殊的主键:时间键。时间键中的数据均为时间日期数据类型,在根据主键查询时可做特殊处理。
在银行交易之类的数据表中,同一账户可能会有很多条交易记录,而所有交易记录中都会有交易时间这样的日期时间数据,在查询时往往又需要根据交易时间去处理,这种情况下可以使用时间键。
下面构建一个银行交易表,存储在文件transaction.btx中:
|
A |
B |
C |
1 |
=create(UID, Amount, Time) |
2021-01-01 |
=5.(12000+rand(9)*1000) |
2 |
for 12 |
=date(2021, A2, 5) |
|
3 |
|
for C1 |
=datetime(B2, time(9+rand(9), rand(60), rand(60))) |
4 |
|
|
>A1.insert(0, #B3, B3, C3) |
5 |
for rand(200)+100 |
=B1+rand(365) |
=time(8+rand(15), rand(60), rand(60)) |
6 |
|
=-(rand(200)+1)*10 |
=datetime(B5, C5) |
7 |
|
>A1.insert(0, int(rand(5)+1), B6, C6) |
|
8 |
=A1.sort(Time).group(UID) |
|
|
9 |
=create(UID, Time, Change, Amount) |
=5.(10000+rand(200)*100) |
>B9.run(A9.insert(0, B9.#, datetime(B1), 0, B9.~)) |
10 |
for A8 |
for A10 |
>B9(#A10)=B9(#A10)+B10.Amount |
11 |
|
|
>A9.insert(0, #A10, B10.Time, B10.Amount, B9(#A10)) |
12 |
=A9.sort(Time) |
transaction.btx |
=file(B12) |
13 |
>C12.export@b(A12) |
=C12.import@b() |
|
A1中创建存取款记录表,表中包括用户编号UID,交易金额Amount和交易时间Time。C1中随机生成5位员工的每月工资如下:
2~4行中的代码生成每月5日的工资转入记录,其中C3随机生成交易时间,在C4中将存入工资的账号,金额和时间存入A1的序表中,执行后A1中数据如下:
5~7行中的代码生成2021年的消费记录,其中B6随机生成消费金额,C6随机生成交易日期时间,在C4中将每笔消费的账号,金额和时间存入A1的序表中,帐号随机生成,执行后A1中添加了消费的数据,如下:
A8中将A1中的数据按交易时间排序后,按用户分组,准备用来生成具体的银行交易数据:
A9中生成银行交易数据表,并在C9中填入各个用户2021年初的账户余额,如下:
数据表中包含四个字段:用户编号UID,交易时间Time,金额变动Change和余额Amount。在10~11行,根据各个用户当年的存取款记录,生成每笔交易后的交易数据,其中C10通过计算改变B10中记录的每位账户的余额,C11将交易后的记录填入A9的交易记录表中。
A12将这些交易数据安装交易时间排序后,得到所需的银行交易数据表,在A13中将其存入文件transaction.btx中。B13中读取交易数据记录如下:
在使用时间键时,需要先用T.keys@t(K1,K2, ..., KT)来定义,添加@t选项时,定义的字段参数中,最后一个为时间键。一个序表只能有一个时间键,其它主键称为基本键。如:
|
A |
B |
1 |
=file("transaction.btx") |
|
2 |
=A1.import@b() |
>A2.keys@t(UID, Time) |
3 |
=A2.find(3, date(2021,5,1)) |
=A2.pfind(3, date(2021,5,1)) |
4 |
=A2.find(3, datetime(2021,8,5,18,0,0)) |
=A2.pfind(3, datetime(2021,8,5,18,0,0)) |
5 |
=A2.find(3) |
=A2.pfind(3) |
B2中,设定序表A2中,基本键为UID,时间键为Time,设定后,A2中数据如下:
可以发现,UID和Time字段都添加了主键标记。
在A3中,用T.find(k) 函数根据主键查找记录,结果如下:
和基本键不同,在T.find() 函数中用时间键查找时,并不是用“相等”的关系判断的,而是“指定时间前的最后记录”。以A3中的表达式为例,A2.find(3, date(2021,5,1))中,查找的是3号客户在2021年5月1日前的最后一笔交易记录。
与T.find() 类似,还可以用T.pfind(k) 函数查找记录序号,如B3中得到的是上面这条记录的序号:
除了使用日期数据,也可以使用时间日期数据来执行有关时间键的查询,如A4和B4中结果如下:
如果序表指定了时间键,但是在使用T.find()或者T.pfind()函数执行主键查询时,未设置时间键的值,此时将把时间键的查询参数设置为当前时间。如A5中查询=A2.find(3)即相当于计算=A2.find(3, now())。由于时间键的序表中存储的数据往往是历史数据,都会发生在现在时刻之前,因此不设定时间键值的查询,相当于查询基本键满足条件的数据中,最新的一条记录。A5和B5中的结果如下:
定义序表的时间键,只能使用T.keys@t(Ki, ..., KT)函数指定,而不能像基本键一样,在用create(C1, C2, …)函数时用#指定。
如果某个序表中有时间键,在表间关联时,也会根据时间键来处理。如使用A.join(C:…, T:K, x:F, …),将序表T中的记录与排列A相关联时,会根据其中的时间键查找记录,如下面的例子:
|
A |
B |
1 |
=file("transaction.btx") |
=demo.query("select EID, NAME, DEPT from EMPLOYEE where EID < 6") |
2 |
=A1.import@b() |
>A2.keys@t(UID, Time) |
3 |
=B1.join(EID, A2, Time, Amount) |
|
4 |
=B1.join(EID:date(2021,5,1), A2, Time, Amount) |
=B1.join(EID:date(2021,5,1), A2:UID:Time, Time, Amount) |
B1中,从员工表中读取前5名员工信息如下:
A2中读取上一节中生成的银行交易文件transaction.btx,并在B2中指定序表的基本键为UID,时间键为Time:
A3中用A.join()函数,将员工信息与银行交易表连接,连接时根据员工编号EID与银行交易表中的记录匹配,从对应记录中获取Time和Amount两个字段,结果如下:
可以发现,由于B1中的员工表并没有日期时间字段,只凭借EID字段执行连接,因此在银行交易表中,会使用当前时刻执行时间键匹配,得到的数据是最后一笔交易的时间和最终账户余额。
A4中执行连接时,指定了时间为2021年5月1日,连接后结果如下:
可以看到,此时查询到的结果是指定时刻前的最后一笔交易状态。使用A.join(C:…, T:K, x:F, …)执行连接时,如果序表T未指定K,则会根据它本身的主键处理,也可以指明连接时使用的主键,如B4中的写法,B4中的结果和A4是相同的。
除了使用A.join执行连接时可以使用时间键,在使用A.switch执行表间关联时,也可以使用时间键操作,如:
|
A |
B |
1 |
=file("transaction.btx") |
=demo.query("select EID, NAME, DEPT from EMPLOYEE where EID < 6") |
2 |
=A1.import@b() |
>A2.keys@t(UID, Time) |
3 |
=B1.derive(Date) |
|
4 |
2021-1-1 |
>A3.run(Date=A4+rand(365)) |
5 |
>A3.switch(EID:Date, A2:UID:Time) |
=A3.new(EID.UID:ID, NAME, Date, EID.Time:Time, EID.Amount:Amount) |
6 |
>B1.switch(EID, A2) |
=B1.new(EID.UID:ID, NAME, EID.Time:Time, EID.Amount:Amount) |
A3中在前面例子中的员工资料表基础上,增加了Date字段,并在第4行的代码中随机填入日期数据,填写后A3中数据如下:
A5中,根据上表中的EID和Date两个字段,与A2中的基本键和时间键做关联,转换为对应记录,执行后A3中结果如下,其中EID字段已转换为对应的银行交易记录:
为了便于了解,在B5中根据连接后的数据整理生成了结果序表如下:
可以看到,从EID的交易记录中,获取到的都是Date指明日期前最后一笔交易后的账户状况。A5的表达式中,A2的主键也可以不指定,此时会使用序表本身的主键设置执行switch操作,得到的结果是相同的。
B1的员工资料表中,并没有日期时间类数据,如果用它执行switch操作,就只能使用默认的主键关联情况了,如A6中的情况。B6中在这种状况下整理出连接结果如下:
可见,此时将用当前时刻执行时间键检索,得到的是最终的账户状态。