简体   繁体   English

SQL Server强制转换和转换DateTime和DateTime2失败

[英]Sql Server Cast & Convert DateTime and DateTime2 Fail Relentlessly

Firstly, Here is some information about my environment: 首先,这是有关我的环境的一些信息:

I'm running a SQL 2005 database on a SQL 2014 instance. 我正在SQL 2014实例上运行SQL 2005数据库。 COLLATION is SQL_Latin1_General_CP1_CI_AS. COLLATION为SQL_Latin1_General_CP1_CI_AS。 Here are the results of my DBCC USEROPTIONS 这是我的DBCC USEROPTIONS的结果

  • textsize 2147483647 文字大小2147483647
  • language us_english 语言us_english
  • dateformat mdy 日期格式
  • datefirst 7 约会第一7
  • lock_timeout -1 lock_timeout -1
  • quoted_identifier SET quoted_identifier SET
  • arithabort SET 阿里哈伯特集
  • ansi_null_dflt_on SET ansi_null_dflt_on设置
  • ansi_warnings SET ansi_warnings SET
  • ansi_padding SET ansi_padding SET
  • ansi_nulls SET ansi_nulls SET
  • concat_null_yields_null SET concat_null_yields_null SET
  • isolation level read committed 隔离级别已提交

Here is my problem. 这是我的问题。

I keep running into the following 2 errors depending on when I try to select from a view and us a WHERE clause against a converted column of type DATETIME or DATETIME2. 根据我何时尝试从视图中进行选择,我们不断遇到以下2个错误,我们对DATETIME或DATETIME2类型的转换列使用了WHERE子句。

(DATETIME2) Msg 241, Level 16, State 1, Line 122 Conversion failed when converting date and/or time from character string. (DATETIME2)消息241,级别16,状态1,第122行从字符串转换日期和/或时间时转换失败。

And... 和...

(DATETIME) Msg 242, Level 16, State 3, Line 122 The conversion of a varchar data type to a datetime data type resulted in an out-of-range value. (日期时间)消息242,级别16,状态3,第122行将varchar数据类型转换为日期时间数据类型导致超出范围的值。

My problem SOUNDS deceptively simple, like I must be a mook and am either passing in an incorrectly formatted value in the WHERE or not taking into account the language settings, collation, and optimizer precedence. 我的问题听起来很简单,就像我必须是一个笨蛋一样,或者在WHERE中传递了格式错误的值,或者没有考虑语言设置,排序规则和优化程序优先级。

So here is my query. 所以这是我的查询。

DECLARE @DATEVALUE DATETIME = '01-05-2015 14:23:05'
SELECT t.* FROM Reports.MyReportView WHERE t.MyDateColumn = @DATEVALUE

This fails MISERABLY no matter what I try. 无论我如何尝试,此操作都会失败。

I have no problem casting and converting character strings to DATETIME. 我完全没有问题,可以将字符串转换为DATETIME。 Like... 喜欢...

SELECT CAST('03/28/2011 18:03:40' AS DATETIME) 

Works just fine. 效果很好。

The problem only seems to happen in my WHERE clause. 该问题似乎仅在我的WHERE子句中发生。 I've looked at tons of suggestions, tried lots of things such as changing the language settings to british or french, changing the DATEFORMAT to ymd, dmy, mdy, tried some other solutions I found such as... 我看了很多建议,尝试了很多事情,例如将语言设置更改为英国或法语,将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) 

...And yes, that outputs a DATETIME just fine. ...而且是的,输出的DATETIME很好。 But the moment I try to use the value in my WHERE clause ... KAAAABOOOOOOOM!!! 但是,当我尝试在WHERE子句中使用该值时……KAAAABOOOOOOOM! So I've had no luck resolving this problem. 所以我没有运气来解决这个问题。

The only thing I can think of is that the optimizer is punking me because it's rearranging the query behind the scenes and I am comparing a VALID datetime variable to an invalid VARCHAR string PRIOR to when I am converting the string in the query order, and so it is the View that is actually causing the failure and has nothing to do with SQL Server's datetime conversions. 我唯一能想到的是,优化器正在对我进行猛击,因为它会在后台重新安排查询,并且我将VALID datetime变量与按查询顺序转换字符串之前的VARCHAR字符串无效进行比较,因此它实际上是导致失败的视图,并且与SQL Server的日期时间转换无关。

Please help. 请帮忙。

UPDATE UPDATE

Ok Fixed. 确定的固定。 I followed advice from everyone and rewrote the date conversion in the View into a SubQuery/SubView and then Joined it. 我遵循了所有人的建议,并将视图中的日期转换重写为SubQuery / SubView,然后将其联接。 Here is what the new conversion code looks like... 这是新的转换代码的样子……

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'

This is embarassing code, but it works, solves the problem and is unfortunately necessary because somebody didn't want to store date values as date columns in a wacky database structure... so maybe it will help somebody who runs into this problem. 这是令人难以置信的代码,但是它可以工作,可以解决问题,并且由于某些人不想将日期值存储为古怪的数据库结构中的日期列而不幸地是必需的……因此,这可能会帮助遇到此问题的人。

If your data column that you are converting from can contain nulls or possibly have invalid date data in it, then you are going to get this error. 如果您要转换的数据列中可能包含空值或其中可能包含无效的日期数据,那么您将收到此错误。 The SQL engine will try to do the CAST on all the potential data BEFORE it filters the data on the WHERE clause. 在过滤WHERE子句中的数据之前,SQL引擎将尝试对所有潜在数据进行CAST。 What you need to do is do a subquery, and then select and cast against that: 您需要做的是执行子查询,然后选择并对其进行强制转换:

SELECT CAST(a.StringField AS datetime) AS TheDate
FROM (
    SELECT a.* FROM MyTable WHERE StringField = '12/1/2014'
) a

OR: 要么:

SELECT CAST(a.StringField AS datetime) AS TheDate
FROM (
    SELECT a.* FROM MyTable WHERE ISDATE(StringField) = 1
) a
WHERE CAST(a.StringField as datetime) = '12/1/2014'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM