我有一个针对SQL Server数据库运行的简单测试查询。
SELECT IsDate('1' + '/' + '25' + '/' + '1993')
当我对数据库运行它时
set dateformat dmy
它正确返回 0
当我对数据库运行它时
set dateformat mdy
它正确返回 1
现在的问题是,当我从 .Net 中的SqlCommand
对象运行此查询时,我没有得到预期的结果。
问题是我将线程的区域性和日期时间格式设置为 d/m/y。 即使我的线程以 d/m/y 格式运行并且我的数据库设置为 d/m/y,当从SqlCommand
运行时,我仍然从我的查询中返回 1
。示例代码:(注意:QuickQuery
只是一个包装方法,它对我选择的数据库运行SqlCommand
)
string query = $" SELECT IsDate('1' + '/' + '25' + '/' + '1993')";
var dt = QuickQuery(query);
return $"{dt.Rows[0][0]}" + $" {new DateTime(1993, 1, 25)}";
此输出 = "1 25/01/1993 00:00:00">
当我的实际数据库和当前线程设置为 d/m/y 时,什么决定了SqlCommand
是否在 m/d/y 上下文中运行?
我已经确认了我的数据库设置
DBCC USEROPTIONS
编辑 1:
只是一个简短的说明 - 我很欣赏关于以更好的方式做事的投入,这是有价值的。对于这种特殊情况,我无法遗憾地选择问题的上下文,我只是可以解决它。我为每个值月、日和年都有一个varchar
列。它们可以是空值或文本。由此,我必须创建与实际datetime
列的日期时间比较,并能够在服务器和正在运行的线程上使用任何日期时间格式!
本质上:完全避免问题。永远不要将日期称为字符串。使用定义和键入良好的参数。
本质上(切换到 Dapper 语法,因为它支持参数):
DateTime date = ...
var dt = connection.QuerySingle<DateTime>("select @date + 2", new {date});
其他数据也是如此 - 数字、小数分隔符和组分隔符也会遇到类似的问题,正确的方法不是学习 SQL Server 想要的格式:它不使用字符串,而是传递参数化值。这也会使意外陷入SQL注入漏洞变得更加困难。