【发布时间】:2015-01-20 17:01:59
【问题描述】:
首先,这里是关于我的环境的一些信息:
我在 SQL 2014 实例上运行 SQL 2005 数据库。 COLLATION 是 SQL_Latin1_General_CP1_CI_AS。这是我的 DBCC USEROPTIONS 的结果
- 文本大小 2147483647
- 语言 us_english
- 日期格式 mdy
- 日期优先 7
- lock_timeout -1
- quoted_identifier 设置
- arithabort 设置
- ansi_null_dflt_on SET
- ansi_warnings 设置
- ansi_padding 设置
- ansi_nulls 设置
- concat_null_yields_null SET
- 已提交隔离级别读取
这是我的问题。
我不断遇到以下 2 个错误,具体取决于我何时尝试从视图中选择以及我们针对 DATETIME 或 DATETIME2 类型的转换列使用 WHERE 子句。
(日期时间2) 消息 241,第 16 级,状态 1,第 122 行 从字符串转换日期和/或时间时转换失败。
还有……
(日期时间) 消息 242,第 16 级,状态 3,第 122 行 将 varchar 数据类型转换为 datetime 数据类型导致值超出范围。
我的问题听起来很简单,就像我一定是个傻瓜,要么在 WHERE 中传递了格式不正确的值,要么没有考虑语言设置、排序规则和优化器优先级。
这是我的查询。
DECLARE @DATEVALUE DATETIME = '01-05-2015 14:23:05'
SELECT t.* FROM Reports.MyReportView WHERE t.MyDateColumn = @DATEVALUE
无论我尝试什么,这都失败了。
我没有问题将字符串转换为 DATETIME。 喜欢...
SELECT CAST('03/28/2011 18:03:40' AS DATETIME)
工作得很好。
问题似乎只发生在我的 WHERE 子句中。我查看了大量建议,尝试了很多方法,例如将语言设置更改为英式或法语,将 DATEFORMAT 更改为 ymd、dmy、mdy,尝试了我找到的其他一些解决方案,例如...
DECLARE @F7 nvarchar(10) = '01/05/2015'
DECLARE @F8 nvarchar(10) = '00:00:00'
DECLARE @NEWTIME DATETIME
DECLARE @Date VARCHAR(20)
SET @Date = RIGHT(@F7,4)+'/'+SUBSTRING(@F7,4,2)+'/'+LEFT(@F7,2)
DECLARE @time DATETIME
SET @time = CONVERT(DATETIME, @Date + ' ' + @F8)
...是的,输出 DATETIME 就好了。但是当我尝试在 WHERE 子句中使用该值时...... KAAAABOOOOOOOM !!!所以我没有运气解决这个问题。
我唯一能想到的是优化器在嘲笑我,因为它在幕后重新安排查询,并且在我按查询顺序转换字符串之前,我正在将 VALID 日期时间变量与无效的 VARCHAR 字符串进行比较,因此实际上是视图导致了失败,并且与 SQL Server 的日期时间转换无关。
请帮忙。
更新
确定已修复。我听从了大家的建议,将视图中的日期转换重写为子查询/子视图,然后加入它。这是新的转换代码的样子...
CONVERT(DATETIME,
CASE
WHEN
(
CASE
WHEN REPLACE(ISNULL(t.DayCol,''),' ','') = ''
THEN NULL ELSE REPLACE(ISNULL(t.DayCol,''),' ','') END
) IS NULL
OR
(
CASE WHEN REPLACE(ISNULL(t.MonthCol,''),' ','') = ''
THEN NULL ELSE REPLACE(ISNULL(t.MonthCol,''),' ','') END
) IS NULL
OR
(
CASE WHEN REPLACE(ISNULL(t.YearCol,''),' ','') = ''
OR t.YearCol = 'NoSelection'
THEN NULL ELSE t.YearCol END
) IS NULL
OR
ISDATE
(
CONCAT
(
RIGHT('0' +REPLACE(MonthCol,' ',''),2),'/',
RIGHT('0' + REPLACE(t.DayCol,' ',''), 2),'/',
REPLACE(YearCol,' ','')
)
) = 0
THEN NULL
ELSE
CONCAT
(
RIGHT('0' +REPLACE(MonthCol,' ',''),2),'/',
RIGHT('0' + REPLACE(t.MonthCol,' ',''), 2),'/',
REPLACE(YearCol,' ','')
)
END) as 'MyDateColumn'
这是令人尴尬的代码,但它有效,解决了问题,不幸的是,这是必要的,因为有人不想将日期值作为日期列存储在古怪的数据库结构中......所以也许它会帮助遇到这个问题的人问题。
【问题讨论】:
-
“这很失败”,“KABOOOM”....你能告诉我们实际发生了什么吗?
-
我推荐的一件事是在您的代码中使用 ISO 8601 日期格式 (
YYYY-MM-DD HH:MM:SS)。这将消除本地化影响事物。然后,如果您使用 ISO 日期并出现错误,则很容易追踪。至于失败,视图的代码在这里会有所帮助。 -
如何在视图中填充日期列?
-
另外,您可能会在 DBA.Stackexchange 上获得更多有用的帮助。这些人中的大多数都非常擅长 TSQL(我曾经是我以前工作中的一员)
-
@ChrisCampbell 服务器本地化选项确定字符串 1/12/2014 如何转换为日期时间,是 2014 年 1 月 12 日还是 2014 年 12 月 1 日(取决于国家/地区)。无论服务器本地化设置是什么,ISO 2014-01-12 总是 2014 年 1 月 12 日。那是我所引用的,而不是 CONVERT 语法。
标签: c# sql-server date datetime