在where子句中将int转换为字符串

时间:2019-01-16 15:40:38

标签: sql-server

我有一个查询,该查询将int文件转换为最新的文件,并且工作正常。但是,当我将此演员表添加到哪里时,我的查询将不起作用

select 
 convert(date,CONVERT(varchar(10),t.TimeEntityElementId,101))  
from dbo.Time t
where  
  convert(date,CONVERT(varchar(10),t.TimeEntityElementId,101))  < N'2019-01-01'

2 个答案:

答案 0 :(得分:0)

为什么不只使用cast()? :

select cast(t.TimeEntityElementId as date)
from dbo.Time t
where cast(t.TimeEntityElementId as date)  < '2019-01-01';

N不适合这样做,因为TimeEntityElementId具有datetime类型,并且N代表“本国语言字符集”,这意味着您正在传递{{1 }},NCHARNVARCHAR类型的数据。

答案 1 :(得分:0)

因此,似乎我们有一个int值,您确实需要一个DateTime。在表定义中更正此错误确实可以为您省去很多的麻烦。但是在这种情况下,我们仍然可以利用现有数据进行一些改进。

从此WHERE条件开始:

convert(date,CONVERT(varchar(10),t.TimeEntityElementId,101))  < N'2019-01-01'

此处使用CONVERT()函数可防止使用TimeEntityElementId可能具有的任何索引。相反,我们可以利用按顺序大小和位置组织的细分来利用值。这类似于Sql Server实际存储日期/日期时间的方式,但是它每年从整数空间中刻出10,000个数字块,而不是像Sql Server那样刻出365。这意味着您可以大大减少代码并编写与简单的数字比较相同的条件,如下所示:

t.TimeEntityElementId  < 20190101

这不需要进行任何逐行转换,并且仍然可以使用TimeEntityElementId索引,因此应该更快地执行 MUCH ,可能是多个数量级。

当然,您仍然需要担心SELECT端,但是现在您只转换通过WHERE子句的行,而不转换表中的每一行,这足以解决问题。但是我们可以做更多。我们还可以使用DATEFROMPARTS()函数来删除SELECT转换:

 DATEFROMPARTS(t.TimeEntityElementId/10000, (t.TimeEntityElementId % 10000) / 100, t.TimeEntityElementId % 100)

这样可以避免将字符串解析为日期时间,这实际上是一个很慢的操作。上面的表达式令人发疯,这全是数学,CPU可以非常高效地完成。解析字符串必须考虑各种文化/国际化的怪癖,因此往往要慢得多。对于TimeEntityElementId具有不符​​合日期格式的行的情况,它也不太敏感。您仍然可以在那里获得奇怪的结果,但至少它不应该只是使整个查询失败。

像这样将它们放在一起:

SELECT
    DATEFROMPARTS(t.TimeEntityElementId/10000, (t.TimeEntityElementId % 10000) / 100, t.TimeEntityElementId % 100)  
FROM dbo.Time t
WHERE t.TimeEntityElementId  < 20190101

但是这些主要是性能方面的改进。他们可能也可以解决您的问题,但这只是一个副作用,我不确定,因为我们对问题出在哪里没有清晰的描述。

这将我带到了最后一点。我们需要更好地了解“无效”的含义。如果没有对错误或错误行为的进一步说明,“不起作用”将永远都不够好。