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查询会产生大量结果,我找不到任何差异。
答案 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