我有一个SQL Server表Companies
,其中包含UserDefined4
类型的列nvarchar(100)
。
此列包含一些文字以及格式为DD.MM.YYYY
我想选择2014年3月和4月的记录。
我正在运行此查询,
SELECT
(Right(Companies.UserDefined4, 10))
FROM
Companies
WHERE
(Right(Companies.UserDefined4, 10) not like '%[^0-9.]%'
AND (Right(Companies.UserDefined4, 10) not like ''))
AND (CONVERT(Date,Right(Companies.UserDefined4, 10),104) >= '2014-03-01'
and
CONVERT(Date,Right(Companies.UserDefined4, 10),104) <= '2014-04-30')
此查询引发错误
将字符串转换为日期和/或时间时出错。
我已经逐一检查了所有记录,并且它们以适当的格式包含日期。对我来说奇怪的是,如果我在同一个查询的后续部分中放置OR
而不是AND
,则会运行相同的查询:
(
CONVERT(Date,Right(Companies.UserDefined4, 10),104) >= '2014-03-01'
OR
CONVERT(Date,Right(Companies.UserDefined4, 10),104) <= '2014-04-30'
)
我知道,将日期保存为NVarChar
并不是明智的决定,但我必须处理这些数据。我不是设计这个数据库的人。
答案 0 :(得分:3)
我过去曾遇到过类似的问题,而且这些问题都是由于某些专栏没有以预期的字符(在你的情况下为日期)和&#34;警卫条款&#34; (在您的情况下,WHERE
中的前两个条件)不会阻止查询引擎应用&#34;范围条件&#34; (在您的情况下,WHERE
中的最后两个条件。)
请注意,我并不确切知道为什么会发生这种情况(可能是查询优化,没有&#34;短路&#34;评估或评估发生的顺序不是我们所期望的 - - 这是我推测的),但是我注意到如果你在一个临时结构(例如一个表变量)中存储查询的中间结果(只有&#34; guard子句&#34;应用)然后应用&#34;范围条款&#34;对于那个中期结果,它将起作用。
例如,即使存在&#34;坏&#34;行(不以日期结束的行):
DECLARE @t TABLE (userdate CHAR(10))
INSERT @t
SELECT RIGHT(Companies.UserDefined4, 10)
FROM Companies
WHERE RIGHT(Companies.UserDefined4, 10) NOT LIKE '%[^0-9.]%'
AND RIGHT(Companies.UserDefined4, 10) <> ''
SELECT *
FROM @t
WHERE CONVERT(DATE, userdate, 104) >= '2014-03-01'
AND CONVERT(DATE, userdate, 104) <= '2014-04-30'
您可以查看演示问题的小提示here。
答案 1 :(得分:2)
你能够确定 UserDefined4
真的始终包含最右边10个字符的那种格式的日期吗?
如果是这样,您可以像这样创建一个计算列:
ALTER TABLE dbo.Companies
ADD DateFromUD4 AS CONVERT(DATE, RIGHT(UserDefined4, 10), 104) PERSISTED
然后查询变得非常简单:
SELECT
(list of columns)
FROM
dbo.Companies
WHERE
DateFromUD4 >= '20140301' AND
DateFromUD4 <= '20140430'
我喜欢使用 ISO-8601 格式(YYYYMMDD
没有任何破折号)将日期指定为字符串,因为这可以保证在任何 SQL上运行服务器,无论日期和语言设置如何。
由于转换为DATE
,您也不必担心时间部分 - 这是仅限日期计算列。这适用于SQL Server 2008 和更新版本。