You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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()

代码说明

  1. index.search()的作用:该方法会返回第一个匹配或大于目标值的记录位置,如果目标值不存在于索引中,不会抛出异常,而是返回合适的插入点,恰好符合区间查询的需求。
  2. 包含端点的处理:
    • 日期区间:通过搜索to_date + 1天的位置作为切片结束点,确保[start_pos:end_pos]包含所有<=to_date的记录。
    • 发票号区间:同理搜索to_inv + 1的位置作为结束点,确保包含所有<=to_inv的记录。
  3. 字段访问优化:使用row.invno、row.invdt等字段名访问数据,比索引下标更清晰易读。

内容的提问来源于stack exchange,提问作者Ravi Kannan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:35:04