这是我的第一个问题,所以请原谅可能发生的任何错误:)
我制作了一个 C# 程序,它使用 Datatables 从 SQL Server 数据库收集数据,然后使用 Interop 将结果导出到 Excel 电子表格。
程序本身运行良好并且按其应有的方式运行;但是,当它尝试使用 Date
选择数据时,我发现了一些错误。小于或等于即 2014-05-31 23:59:59
的列.
假设我尝试获取截至 2014 年 5 月 1 日的所有数据。
我的代码首先为稍后使用的 SQL 命令启动“开始日期”参数,如下所示:
var firstDay = new DateTime(today.Year, today.Month, 1); //2014-05-01 00:00:00`
基于firstDay
,它启动参数的日期
var periodTo = firstDay.AddSeconds(-1);`
我调试并得到了我想要的时间:2014-04-30 23:59:59
为数据条件添加更多参数后,它会执行使用提供的参数运行查询的方法。
queryResult = medicore.GenerateRegister(ConfigurationManager.AppSettings["queryDir"], ConfigurationManager.AppSettings["queryName"]);`
periodTo
参数将映射到@EDate
SQL 脚本中的变量。 @EDate
声明为Datetime
。 @Edate
在这里发挥作用:
Select columns
From tables
Where Voucher.Date <= @EDate
我想,脚本将类似于 Where Voucher.Date <= '2014-04-30 23:59:59'
问题是,生成的 Excel 文件中的结果还包含来自 '2014-05-01'
的数据。 ,这不应该存在......至少根据我设定的标准。
C# 和 SQL Server 之间是否发生了某种舍入?
谢谢!
最佳答案
原因可能是 Voucher.Date
是 SMALLDATETIME
,因此您隐式转换 '2014-04-30 23:59:59 '
到 SMALLDATETIME
:
SET DATEFORMAT MDY;
SELECT CONVERT(SMALLDATETIME, '2014-04-30 23:59:59')
这给出了“2014-05-01”。
为什么不直接使用小于运算符,而不是使用小于或等于?
SET DATEFORMAT MDY;
SELECT ...
WHERE Voucher.Date < '2014-05-01';
注意,我已经明确说明了DATEFORMAT
,因为yyyy-MM-dd
(尽管是ISO标准)对于DATETIME
来说不是文化不变的SQL Server 中的 > 和 SMALLDATETIME
数据类型,如果(像我一样)您所在的国家/地区默认日期格式为 DMY
,则 SELECT CONVERT(SMALLDATETIME, '2014-04-30')
会给你一个转换错误。 yyyyMMdd
是这两种类型的唯一区域性不变的日期格式。
Aaron Bertrand 的 Bad habits to kick : mis-handling date / range queries 是一篇优秀且非常相关的文章,值得一读。
关于C# 程序想要选择数据 <= 23 :59:59 but ends up selecting data with 00:00:00 timestamp as well,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27376054/