SQL:将varchar转换为datetime时出错

时间:2016-08-03 10:52:33

标签: sql sql-server datetime type-conversion

WITH Valid_dates (ValidDate)
AS
(
    SELECT '19' + SUBSTRING(column, 0, 3) + '-' + SUBSTRING(column, 3, 2) + '-' + SUBSTRING(column, 5, 2) AS ValidDate
    FROM table
    WHERE SUBSTRING(column, 3, 2) <= '12' --Max month
    AND SUBSTRING(column, 3, 2) >= '01' --Min month
    AND ISNULL(SUBSTRING(column, 3, 2), '') <> '' --Empty string
    AND SUBSTRING(column, 5, 2) <= '31' --Max day
    AND SUBSTRING(column, 5, 2) >= '01' --Min month
    AND ISNULL(SUBSTRING(column, 5, 2), '') <> '' --Empty string
    AND LEN('19' + SUBSTRING(column, 0, 3) + '-' + SUBSTRING(column, 3, 2) + '-' + SUBSTRING(column, 5, 2)) = 10 --Must match 10 character format
)

SELECT CONVERT(DATETIME, ValidDate)
FROM Valid_dates

当我在SQL Server Management Studio中执行此查询时,收到以下错误消息:“将varchar数据类型转换为日期时间数据类型会导致超出范围的值。”

我已过滤掉所有无效日期。 2月30日,4月31日,6月31日等不存在的日期本身并没有被过滤掉,但是我已经检查了它们,但它们并不存在。仅运行CTE查询会产生大量结果,我找不到任何差异。

2 个答案:

答案 0 :(得分:1)

这是SQL Server的问题。它不保证查询中子句的评估顺序。没有任何感觉where(即使在CTE中)被评估&#34;之前&#34;其余的查询。

注意:这是优化程序的功能。通过重新排列查询的不同组件的评估,优化器可以创建更好的查询计划。

在SQL Server 2012+中,最简单的方法是TRY_CONVERT()

with . . .
select try_convert(datetime, validdate)
from valid_dates;

在早期版本中,您可以使用case

select (case when <all your conditions here>
             then convert(datetime, validdate)
        end)

SQL Server 确实保证在正常情况下对case语句进行顺序评估(有一些奇怪的聚合情况),所以这也解决了这个问题。

答案 1 :(得分:0)

我很确定这与文化有关。

你没有指定实际的输入,从你的代码我想它是一些未分离的格式,没有像920130那样意味着1992年1月30日?

这将转换为1992-01-30

您的默认文化可能是使用类似yyyy-dd-mm的内容,这会导致超出范围的错误,其中“月”高于12 ...

尝试使用102作为文化键:

SELECT CONVERT(DATETIME, ValidDate,102)
FROM Valid_dates

更新

如果我的假设是正确的,那么尝试

会容易得多
SELECT TRY_CAST('19' + column AS DATE) FROM table

SQL Server允许本地生成看起来像yyyymmdd的未分离字符串。如果无法投射,使用TRY_CAST将返回NULL

旧版本(&lt; 2012)使用此

SELECT CASE WHEN ISDATE('19' + column)=1 THEN CAST('19' + column AS DATE) ELSE NULL END FROM table