WPF中VB.NET日期范围日期列表查询SQL适配求助
问题排查要点
日期列表生成功能(bb_Click事件)存在的问题
- SQL语句末尾多余
GO关键字:该关键字是SSMS等客户端专用的批处理分隔符,ADO.NET接口无法识别,执行会直接报错 - 参数赋值冲突:已经通过VB.NET代码给
@StartDate、@EndDate参数传值,SQL内部又写了SELECT语句给这两个参数赋值,会导致参数值被覆盖 - 结果读取方式错误:使用
ExecuteNonQuery()方法仅执行语句不返回查询结果,该方法仅适用于INSERT/UPDATE/DELETE类无结果集的操作,查询日期列表需要用结果读取接口拉取数据 - 日期赋值不规范:直接将字符串赋值给Date类型,未做显式转换,容易因系统区域日期格式差异导致解析错误
用户日期关联展开功能(dg_Click事件)存在的问题
- 变量未初始化:
user_id、from_date、to_date三个变量仅声明未赋值,直接传入参数会触发空值异常 - 重复插入测试数据:每次点击事件都执行INSERT语句往sqltable4写入固定测试数据,多次运行会导致表内出现大量重复数据
- 结果读取方式错误:同样使用
ExecuteNonQuery()方法,查询生成的用户-日期对应结果集完全没有被读取,自然和预期输出不符 - 日历生成逻辑冗余:CTE生成的日历序列未限制最大截止日期,会生成大量超出业务范围的无效日期
可运行代码示例
1. 指定起止日期范围生成日期列表
需要提前在WPF页面添加一个名为DateListGrid的DataGrid控件用于展示结果,代码如下:
Private Sub bb_Click(sender As Object, e As RoutedEventArgs) ' 显式指定日期,避免格式解析错误 Dim StartDate As Date = #2021-11-01# Dim EndDate As Date = #2021-12-01# Dim resultDt As New DataTable() ' 连接字符串按自己的实际环境修改 Using connection As New SqlConnection("Data Source=DESKTOP-D32ONKB\SQLEXPRESS;Initial Catalog=master;Integrated Security=True") ' 去掉GO、去掉内部参数赋值,直接使用传入的参数 Dim cmd As New SqlCommand(" WITH ListDates(AllDates) AS ( SELECT @StartDate AS DATE UNION ALL SELECT DATEADD(DAY,1,AllDates) FROM ListDates WHERE AllDates < @EndDate) SELECT AllDates FROM ListDates OPTION (MAXRECURSION 0)", connection) ' 添加参数 cmd.Parameters.Add("@StartDate", SqlDbType.Date).Value = StartDate cmd.Parameters.Add("@EndDate", SqlDbType.Date).Value = EndDate ' 用DataAdapter拉取结果填充到DataTable Dim da As New SqlDataAdapter(cmd) da.Fill(resultDt) End Using ' 绑定结果到界面控件 DateListGrid.ItemsSource = resultDt.DefaultView End Sub
注意:递归CTE默认最大递归深度是100,如果日期范围超过100天需要加
OPTION (MAXRECURSION 0)解除递归限制,避免报错。
2. 关联用户ID与区间日期展开每日明细
提前在WPF页面添加一个名为UserDateGrid的DataGrid控件用于展示结果,代码如下:
Private Sub dg_Click(sender As Object, e As RoutedEventArgs) Dim resultDt As New DataTable() ' 连接字符串按自己的实际环境修改 Using connection As New SqlConnection("Data Source=DESKTOP-D32ONKB\SQLEXPRESS;Initial Catalog=master;Integrated Security=True") ' 去掉每次插入测试数据的逻辑,优化日历生成范围,直接查询结果 Dim cmd As New SqlCommand(" -- 测试数据仅需手动插入一次,不需要每次执行都插入 -- insert into sqltable4 values -- (1, '2019-02-20', '2019-02-23'), -- (2, '2019-02-22', '2019-02-28'), -- (3, '2019-03-01', '2019-03-05'); WITH rows AS ( SELECT TOP 1000 n = 1 FROM sys.messages ), tally AS ( SELECT n = ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) - 1 FROM rows ), dateRange AS ( SELECT MIN(from_date) AS minDate, MAX(to_date) AS maxDate FROM sqltable4 ), calendar AS ( SELECT DATEADD(dd, n, minDate) AS [date] FROM tally CROSS JOIN dateRange WHERE DATEADD(dd, n, minDate) <= maxDate ) SELECT s.user_id, c.[date] FROM sqltable4 s CROSS JOIN calendar c WHERE c.[date] BETWEEN s.from_date AND s.to_date ORDER BY s.user_id, c.[date];", connection) Dim da As New SqlDataAdapter(cmd) da.Fill(resultDt) End Using ' 绑定结果到界面控件 UserDateGrid.ItemsSource = resultDt.DefaultView End Sub
注意:sqltable4的测试数据只需要手动在数据库执行一次插入即可,不需要写在点击事件里每次运行都插入;SQL中日期统一用
yyyy-MM-dd的ISO格式,避免区域格式解析错误。
效果参考
- 问题运行结果:

- 预期实现结果:

内容的提问来源于stack exchange,提问作者Hema Latha
相关产品推荐
相关产品推荐

