miniob - select tables 实现解析
代码部分主要是在do_select里完成,由于原代码对于多表的支持并不友好,所以不推荐直接在原代码的基础上直接改(否则后面处理查询相关的题目会很麻烦)。
表查询的语法结构是这样的:
select attr_list from table_list where condition_list;
其中list
的数目不定。
为了简化思路,我们不区分单表与多表。
首先我们解析table_list
, 使用一个unordered_map<string,int>
来存储表名与对应的序号, 通过DefaultHandler::get_default().find_table
来查找表名对应的表结构, 如果表不存在,直接返回FAILURE。
然后对每个表都进行一次scan_record
操作, 对应的filter
直接给nullptr
, 即全部读取(当然也可以取出只与该表相关的条件组成一个filter
进行过滤,见原代码), 将表数据用vector<string>
来保存。
至此我们已经可以获得所有表的数据, 然后就是进行笛卡尔积操作。 很多同学都想当然地用循环来进行笛卡尔积, 这在表数目很少的时候当然没问题, 而且出错机率也小, 但如果数据量比较大时,内存装不下。 笛卡尔积的经典做法是深度优先搜索算法或者回溯算法,将所有可能的表记录都进行联结,然后将结果即联结表保存在vector<string>
中(或者在联结过程中进行投影操作,这样对内存的要求要小些)。
对于联结表的过滤问题, 我们可以利用原代码提供给我们的CompositeConditionFilter
类进行过滤,这需要一些小修改(只需要将各个表在联结表记录对应的偏移量叠加到原表偏移量即可). 用上述filter
对联结表进行条件过滤,获得所求的记录,并对该纪录进行投影操作(见原代码对单表的投影操作),获得一个TupleSet
。
* 我们在遍历查询的表与属性时,要反序遍历,即从selects.attr_num - 1到0,这样才跟查询语句的顺序一致(小坑)
* 单表支持的属性类型: \*,id.\*,id.id,id
单表只有一个属性id时,我们可以为它添加一个表名,即当前查询的单表
* 多表支持的属性类型: \*,id.\*,id.id
* 在调用`TupleSet::print`时,最好将表数目作为一个参数传递过去(因为我们无法从`TupleSet`获得表数目),然后根据表数目决定是否打印表名