VB.NET结合SQL Server用DateTimePicker查询带时间区间仅按日期返回
问题场景
- 开发环境:VB.NET 2015 搭配 SQL Server 2012
- 业务需求:查询指定日期、时间区间内的销售交易记录,示例查询范围为2021年3月1日14:00至2021年3月2日08:00的交易数据
- 数据基础:SQL Server的RECEIPTS表中存储交易时间的字段为Datetime类型,存储精度达到毫秒级,示例值为
2021-03-02 16:27:33.233;查询的起止时间参数来自已启用时间选择功能的DateTimePicker控件 - 异常表现:查询执行后仅返回日期匹配的记录,未按照设置的时间条件做过滤
已实现的查询代码
Dim tbls As New DataTable() ' 被注释的旧版SQL语句 ' cmd = New SqlCommand("Select * from RECEIPTS WHERE Time BETWEEN @dafrom AND @dato ORDER BY 'Receipt_No'", con) cmd = New SqlCommand("Select * from RECEIPTS WHERE Date Between @Stim And @Etim ORDER BY 'Receipt_No'", con) cmd.Parameters.Add("@Stim", SqlDbType.DateTime).Value = Datefrom.Value cmd.Parameters.Add("@Etim", SqlDbType.DateTime).Value = DateTo.Value Dim adapter As New SqlDataAdapter(cmd) adapter.Fill(tbls)
问题原因定位
- 基础写法正确:原代码采用参数化查询传递日期值,不存在SQL注入风险,问题均出在SQL语法解析和控件配置环节。
- 核心语法错误:原SQL语句中把存储时间的字段直接写为
Date,未加方括号标注。Date是SQL Server的内置函数,返回不带时间部分的当前日期值,解析器不会将其识别为表中的字段,实际比较逻辑变成用纯日期值和参数做匹配,完全不会触发表中存储的毫秒级时间值的比较。 - 排序语法错误:原SQL的排序字段用单引号包裹为
'Receipt_No',单引号内的内容会被解析为字符串常量,排序逻辑完全失效,该问题不影响时间过滤,但会导致结果排序不符合预期。 - 控件值的潜在偏差:若DateTimePicker未正确配置格式,即使开启了时间选择入口,实际赋值给Value的内容可能仅保留日期部分(时间固定为00:00:00),此时查询条件实际变成匹配两个日期范围内的所有日期,自然不会按具体时间过滤。
- 精度匹配偏差:SQL Server的Datetime类型支持3.33毫秒精度,若结束时间参数未做边界补全,可能漏掉刚好落在查询边界点的毫秒级记录。
修正方案
- 修正SQL语法:将作为字段名的
Date用方括号包裹,明确告知解析器这是表字段而非内置函数;去掉排序字段外的单引号,使用真实字段名排序。修正后的SQL参考:Select * from RECEIPTS WHERE [Date] BETWEEN @Stim AND @Etim ORDER BY Receipt_No - 校验DateTimePicker的实际传值:
- 确保控件
Format属性设置为Long或自定义格式,格式串包含小时、分钟占位符(如"yyyy-MM-dd HH:mm:ss") - 传递参数时直接使用控件的Value属性,不要额外调用
.Date方法(该方法会强制将时间部分重置为00:00:00)
- 确保控件
- 补全结束时间的精度边界:因SQL Server Datetime类型的毫秒精度为3.33毫秒,可将结束时间参数额外增加999毫秒,确保覆盖查询范围内所有毫秒级时间的记录。修正后的VB代码参考:
Dim tbls As New DataTable() ' 修正字段标记和排序语法 cmd = New SqlCommand("Select * from RECEIPTS WHERE [Date] Between @Stim And @Etim ORDER BY Receipt_No", con) cmd.Parameters.Add("@Stim", SqlDbType.DateTime).Value = Datefrom.Value ' 补全999毫秒,覆盖边界点的毫秒级记录 cmd.Parameters.Add("@Etim", SqlDbType.DateTime).Value = DateTo.Value.AddMilliseconds(999) Dim adapter As New SqlDataAdapter(cmd) adapter.Fill(tbls)
内容的提问来源于stack exchange,提问作者Fayemi oladele
相关产品推荐
相关产品推荐

