使用Python dbf模块查询日期区间数据遇NotFoundError问题求助
解决dbf模块区间查询时的NotFoundError异常问题
问题描述
使用dbf模块查询product.dbf表中满足以下条件的记录时,当区间端点值不存在于表中,会抛出dbf.NotFoundError: 'dbf.Index.index_search(x): x not in Index'异常:
- 发票日期在2023-01-23至2023-01-25(包含两端)的产品
- 发票号在2010至2015(包含两端)的产品
测试表数据如下:
invno invdt hsn mname packg 2010 2023-01-21 30086666 Medicine01 10'S 2010 2023-01-23 30044444 Medicine02 10'S 2010 2023-01-23 30043333 Medicine03 15'S 2010 2023-01-23 30049999 Medicine04 15'S 2011 2023-01-24 30049999 Medicine05 15'S 2011 2023-01-24 30049999 Medicine06 15'S 2011 2023-01-24 30049444 Medicine07 30'ML 2011 2023-01-24 30049333 Medicine08 30'ML 2011 2023-01-26 30049111 Medicine09 30'ML 2011 2023-01-26 30049111 Medicine09 30'ML 2012 2023-01-31 30042333 Medicine10 60'S 2012 2023-01-31 30042234 Medicine11 15'S
原出错代码:
import dbf import datetime table = dbf.Table('product.dbf') table.open(dbf.READ_ONLY) index = table.create_index(lambda rec: rec.invdt) # 搜索2023-01-23至2023-01-25的记录,包含两端日期 fromdate = index.index_search(match=(datetime.datetime.strptime('23-01-2023','%d-%m-%Y').date())) todate = index.index_search(match=(datetime.datetime.strptime('25-01-2023','%d-%m-%Y').date())) for row in index[fromdate:todate]: print(row[0],row[1],row[2],row[3],row[4]) # 发票号区间查询也存在同样问题,当目标发票号(如2015)不存在时抛出异常 index = table.create_index(lambda rec: rec.invno) # 搜索发票号2010至2015的记录,包含两端号码 frominv = index.index_search(match=(2010,)) toinv = index.index_search(match=(2015,)) table.close()
解决方案
核心问题是index.index_search()在匹配值不存在时会直接抛出异常,改用index.search()方法可以避免这个问题——该方法会返回匹配或最接近的结果位置,不会报错。同时结合索引切片的特性,实现包含区间端点的查询:
修改后的完整代码
import dbf import datetime table = dbf.Table('product.dbf') table.open(dbf.READ_ONLY) # -------------------------- # 日期区间查询(2023-01-23 至 2023-01-25) # -------------------------- date_index = table.create_index(lambda rec: rec.invdt) from_date = datetime.datetime.strptime('23-01-2023', '%d-%m-%Y').date() to_date = datetime.datetime.strptime('25-01-2023', '%d-%m-%Y').date() # 使用search获取起始位置,若不存在则返回第一个大于等于目标值的位置 start_pos = date_index.search(match=(from_date,)) # 搜索to_date的下一天作为结束点,确保包含所有<=to_date的记录 next_day = to_date + datetime.timedelta(days=1) end_pos = date_index.search(match=(next_day,)) # 遍历区间内的记录 print("日期区间查询结果:") for row in date_index[start_pos:end_pos]: print(row.invno, row.invdt, row.hsn, row.mname, row.packg) # -------------------------- # 发票号区间查询(2010 至 2015) # -------------------------- invno_index = table.create_index(lambda rec: rec.invno) from_inv = 2010 to_inv = 2015 # 获取起始位置 start_inv_pos = invno_index.search(match=(from_inv,)) # 搜索to_inv+1作为结束点,确保包含所有<=to_inv的记录 end_inv_pos = invno_index.search(match=(to_inv + 1,)) # 遍历区间内的记录 print("\n发票号区间查询结果:") for row in invno_index[start_inv_pos:end_inv_pos]: print(row.invno, row.invdt, row.hsn, row.mname, row.packg) table.close()
代码说明
index.search()的作用:该方法会返回第一个匹配或大于目标值的记录位置,如果目标值不存在于索引中,不会抛出异常,而是返回合适的插入点,恰好符合区间查询的需求。- 包含端点的处理:
- 日期区间:通过搜索
to_date + 1天的位置作为切片结束点,确保[start_pos:end_pos]包含所有<=to_date的记录。 - 发票号区间:同理搜索
to_inv + 1的位置作为结束点,确保包含所有<=to_inv的记录。
- 日期区间:通过搜索
- 字段访问优化:使用
row.invno、row.invdt等字段名访问数据,比索引下标更清晰易读。
内容的提问来源于stack exchange,提问作者Ravi Kannan
相关产品推荐
相关产品推荐

