如何为kdb/q数据表中的运行(run)生成ID列?
解决kdb/q中按运行周期分配ID列的问题
问题说明
原始数据表
t:([]a:458 902 458 902 458 902 458 902; b:`newcol1`new2`newcol1`new2`newcol1`new2`newcol1`new2; c:`s`e`e`s`s`e`e`s)
ID分配规则
- 列
a的值唯一,但不绑定单个运行周期(run) - 运行周期以
c=s启动,c=e结束,c=d属于当前运行过程 - 同一
a值的运行完成(包含s和e)后,新运行需分配新ID - 若
a值的记录以e开头,该e需单独分配唯一ID
期望目标表
a b c ID 458 newcol1 s 1-458 902 new2 e 2-902 458 newcol1 e 1-458 902 new2 s 3-902 458 newcol1 s 4-458 902 new2 e 3-902 458 newcol1 e 4-458 902 new2 s 5-902
解决方案
核心思路是通过scan逐行处理数据,维护一个状态字典跟踪每个a的当前运行状态(是否处于活跃运行、当前ID),根据规则动态生成新ID。
实现代码
// 初始化状态字典:key为a的值,value为(是否处于活跃运行, 当前ID) initState:()!(); // 定义扫描函数,逐行生成ID并更新状态 assignId:{[state; row] a:row[`a]; c:row[`c]; // 若a未在状态字典中,初始化其状态 if[not a in key state; state[a]:(0b; 0)]; isActive:state[a][0]; currId:state[a][1]; newId:currId; newIsActive:isActive; // 根据c的类型和当前状态判断ID生成规则 $[ c=`s & not isActive; newId:1+max 0,value state[;1]; newIsActive:1b; c=`e & not isActive; newId:1+max 0,value state[;1]; newIsActive:0b; c=`e & isActive; newIsActive:0b; c=`d; newIsActive:isActive; 1b; :: ]; // 更新当前a的状态 state[a]:(newIsActive; newId); // 返回更新后的状态和生成的ID字符串 (state; string[newId],"-",string[a]) }; // 应用扫描函数处理表,添加ID列 result:update ID:last each assignId\[initState; t] from t;
代码解释
- 状态字典:用字典存储每个
a的运行状态,确保能跟踪每个a是否有未结束的运行,以及当前使用的ID - 扫描逻辑:
- 当遇到
s且a无活跃运行时,生成新ID并标记为活跃 - 当遇到
e且a无活跃运行时,生成新ID并标记为非活跃(单独的e记录) - 当遇到
e且a有活跃运行时,沿用当前ID并标记为非活跃(结束当前运行) - 当遇到
d时,沿用当前ID并保持活跃状态(仅当之前处于活跃运行)
- 当遇到
- ID生成:新ID取当前所有已用ID的最大值加1,保证全局唯一性
内容的提问来源于stack exchange,提问作者Pey Blake
相关产品推荐
相关产品推荐

