Sql 从字符串错误转换日期和/或时间时,导致转换失败的CTE
我创建了一个非常简单的示例,展示了我在使用动态SQL进行更复杂的查询时遇到的一个问题,我无法理解为什么CTE会导致错误,而标准版本不是 使用CTE时出错: 从字符串转换日期和/或时间时,转换失败 我试图通过动态查询实现以下目标: 在本例中,标记与指定数据类型日期不匹配的记录。如果它们通过了该步骤,则稍后将对照查找表对其进行检查,以验证它们是否是我希望在指定范围内验证日期的值Sql 从字符串错误转换日期和/或时间时,导致转换失败的CTE,sql,sql-server-2008,tsql,common-table-expression,Sql,Sql Server 2008,Tsql,Common Table Expression,我创建了一个非常简单的示例,展示了我在使用动态SQL进行更复杂的查询时遇到的一个问题,我无法理解为什么CTE会导致错误,而标准版本不是 使用CTE时出错: 从字符串转换日期和/或时间时,转换失败 我试图通过动态查询实现以下目标: 在本例中,标记与指定数据类型日期不匹配的记录。如果它们通过了该步骤,则稍后将对照查找表对其进行检查,以验证它们是否是我希望在指定范围内验证日期的值 -- Table Setup CREATE TABLE #ValidDate ( V INT IDENTI
-- Table Setup
CREATE TABLE #ValidDate
(
V INT IDENTITY (1, 1) NOT NULL,
VDate DATE NULL
)
INSERT INTO #ValidDate
VALUES ('02/20/2014'), ('02/21/2014'), ('02/22/2014'), ('02/23/2014'), ('02/25/2014')
CREATE TABLE #DatesToValidate
(
I INT IDENTITY (1, 1) NOT NULL,
IDate VARCHAR(30) NULL
)
INSERT INTO #DatesToValidate
VALUES ('apple'), ('02/21/2014'), ('orange'), ('02/23/2014')
CREATE TABLE #Errors
(
ID INT,
Dates VARCHAR(30)
)
INSERT INTO #Errors
SELECT *
FROM #DatesToValidate
WHERE ISDATE(IDate) <> 1
以下是CTE不工作的原因:
;WITH CTE AS
(
SELECT *
FROM #DatesToValidate
WHERE I NOT IN ( SELECT ID
FROM #Errors)
)
SELECT *
FROM CTE
WHERE IDate NOT IN ( SELECT VDate
FROM #ValidDate)
此特定部分失败,因为VDate是日期类型列,IDate是varchar。因此,您需要像castVDate一样将VDate强制转换为varchar30,如下所示 这里有小提琴演示吗 这样试试你的sql
;WITH CTE AS
(
SELECT *
FROM DatesToValidate
WHERE I NOT IN ( SELECT ID
FROM Errors)
)
SELECT *
FROM CTE
WHERE IDate NOT IN (SELECT cast(VDate as varchar(30)) <--- Cast Here
FROM ValidDate)
此特定部分失败,因为VDate是日期类型列,IDate是varchar。因此,您需要像castVDate一样将VDate强制转换为varchar30,如下所示 这里有小提琴演示吗 这样试试你的sql
;WITH CTE AS
(
SELECT *
FROM DatesToValidate
WHERE I NOT IN ( SELECT ID
FROM Errors)
)
SELECT *
FROM CTE
WHERE IDate NOT IN (SELECT cast(VDate as varchar(30)) <--- Cast Here
FROM ValidDate)
这说明了问题所在。两个版本都不能保证工作。如果交换中条件的顺序,则会导致转换失败
在这种情况下,和版本正常工作的原因是短路。当第一个条件失败时,第二个条件无法运行。这是SQL Server可以利用的优化。在这种情况下确实如此,所以你认为它是有效的
CTE版本不起作用,因为无法保证操作的顺序。SQL Server决定做一些不同的事情。也就是说,它试图将“苹果”作为日期进行评估
正确的解决方案是在比较之前进行强制转换。因为演员可能不起作用,你需要小心。为此,您应该使用SQL Server中的用例;它是保证顺序评估的唯一结构
那么,试试这个:
;WITH CTE AS
(
SELECT *
FROM DatesToValidate
WHERE I NOT IN ( SELECT ID
FROM Errors)
)
SELECT *
FROM CTE
WHERE (case when isdate(IDate) = 1 then cast(IDate as date)
end) NOT IN ( SELECT VDate
FROM ValidDate)
这说明了问题所在。两个版本都不能保证工作。如果交换中条件的顺序,则会导致转换失败
在这种情况下,和版本正常工作的原因是短路。当第一个条件失败时,第二个条件无法运行。这是SQL Server可以利用的优化。在这种情况下确实如此,所以你认为它是有效的
CTE版本不起作用,因为无法保证操作的顺序。SQL Server决定做一些不同的事情。也就是说,它试图将“苹果”作为日期进行评估
正确的解决方案是在比较之前进行强制转换。因为演员可能不起作用,你需要小心。为此,您应该使用SQL Server中的用例;它是保证顺序评估的唯一结构
那么,试试这个:
;WITH CTE AS
(
SELECT *
FROM DatesToValidate
WHERE I NOT IN ( SELECT ID
FROM Errors)
)
SELECT *
FROM CTE
WHERE (case when isdate(IDate) = 1 then cast(IDate as date)
end) NOT IN ( SELECT VDate
FROM ValidDate)
作为将来的参考,MySql与SQL Server是一个完全不同的DBMS,它们不应该被标记为相同的。您能提供关于不工作的更多详细信息吗?作为将来的参考,MySql与SQL Server是一个完全不同的DBMS,它们不应该被标记为相同的。您能提供关于不工作的更多详细信息吗?