这很奇怪。我有一个varchar(8000)
类型的列。我们会在其中保存各种数据,如数字,文本,日期等。
我编写了一个简单的选择查询,以便从表格中获取所有“日期”值,我也可以使用CAST
或Convert
以此格式2014-12-16 00:00:00.000
获取我的值。
现在我正在尝试添加where
子句来过滤今年的信息,但是我收到错误:
从字符串转换日期和/或时间时转换失败。
当我在我的选择查询中使用TOP 10000时,错误消失了。这真的很奇怪
; WITH TempTable AS
(
SELECT
ID, CAST(Value AS DateTime) [SomeDate]
FROM
SampleTable
WHERE
ColType = 'Date'
)
SELECT *
FROM FROM TempTable
WHERE [SomeDate] BETWEEN '1/1/2017' AND '12/30/2017'
抛出
从字符串转换日期和/或时间时转换失败。
; WITH TempTable AS
(
SELECT TOP 100000
ID, CAST(Value AS DateTime) [SomeDate]
FROM
SampleTable
WHERE
ColType = 'Date'
)
SELECT *
FROM FROM TempTable
WHERE [SomeDate] BETWEEN '1/1/2017' AND '12/30/2017'
这很好用。请注意我的结果中只有25行。前100000只是我用过的一大数字。我的TOP关键字如何使我的查询变得很好,这很奇怪。
更新:
以下是我不使用TOP关键字进行解析的方法。我把我的查询分开了一点,如下所示。谢谢大家的时间和意见。
;WITH GetAllIDs
AS (
SELECT ID
FROM SampleTable
WHERE ColType = 'Date'
)
,FinalTable
AS (
SELECT ID
,(
SELECT Cast([Value] AS DATETIME)
FROM SampleTable dt
WHERE dt.ID = tt.ID
AND dd.ColType = 'Date'
) [SomeDate]
FROM GetAllIDs tt
)
SELECT *FROM FinalTable
WHERE [SomeDate] BETWEEN '1/1/2017' AND '12/30/2017'
答案 0 :(得分:2)
SQL语句中没有执行顺序。因此,where
子句(必然)在转换值之前过滤行。因此,你的问题。
在SQL Server 2012+中,有一个使用try_convert()
的简单解决方案:
With TempTable AS (
select ID, try_convert(datetime, Value) as SomeDate
from SampleTable
where ColType = 'Date'
)
Select *
from TempTable
Where SomeDate between '2017-01-01' and '2017-12-30';
Microsoft认为此行为是优化程序的功能,而不是错误(我不同意)。它为优化查询提供了更多机会。在这种情况下,简单的转换是在读取数据时完成的,而不是在处理管道的下游。
请注意,我还将日期常量更改为YYYY-MM-DD格式。您应始终使用YYYY-MM-DD或YYYYMMDD作为格式。
添加TOP
时这种情况消失的事实是执行计划的一些奇怪的工件。出于某种原因,这将在评估表达式之前进行过滤。我知道TOP
有时会产生这种影响。我在这种情况下感到惊讶,因为查询很简单。
编辑:
在SQL Server 2008中,您可以使用case
。像这样:
With TempTable AS (
select ID, (case when isdate(value) = 1 then convert(datetime, Value) end) as SomeDate
from SampleTable
where ColType = 'Date'
)
Select *
from TempTable
Where SomeDate between '2017-01-01' and '2017-12-30';
case
表达式保证了参数的评估顺序。仅在when
。
then
答案 1 :(得分:0)
基于SQL 2008,您必须更改模式。
首先,为什么它适用于TOP命令。 TOP选择查询中与WHERE子句匹配的所有记录,直到TOP的限制。由于您具有WHERE子句,因此具有TOP的版本仅将具有Coltype为“Date”的记录传递到日期检查。如果没有顶部,优化器会认为根据日期范围检查Value列的值将比过滤列类型更快,因为只需要检索一个数据元素来检查“加速”(在这种情况下,吹up)查询。
应该使用的一个选项是将TempTable定义代码更改为:
; WITH TempTable AS
(
SELECT TOP 100 PERCENT
ID, CAST(Value AS DateTime) [SomeDate]
FROM
SampleTable
WHERE
ColType = 'Date'
)
另一个明显的选择是将所有值提取到实际的临时表,而不是直接使用CTE,然后查询该表。
答案 2 :(得分:0)
请参阅我的更新:这是我最终解决问题的方法。感谢Gordon,Laughing Vergil的意见。