这些SQL语句之间有什么区别

时间:2016-04-09 12:46:35

标签: sql sql-server sql-server-2008

此声明有效:

DECLARE @variable_name INT

SET @variable_name = (SELECT DATEPART(DAYOFYEAR, GETDATE()))

SELECT *
FROM   artists
WHERE  SUBSTRING(DOB, 0, 5) > '1900'
       AND CONVERT(INT, DATEPART(DAYOFYEAR, DOB)) = @variable_name

这个不起作用:

SELECT *
FROM   artists
WHERE  SUBSTRING(DOB, 0, 5) > '1900'
       AND CONVERT(INT, DATEPART(DAYOFYEAR, DOB)) = 
                        (SELECT CONVERT(INT, datepart(DAYOFYEAR, getdate()))) 

它返回错误

  

Msg 242,Level 16,State 3,Line 1
  将varchar数据类型转换为日期时间数据类型会导致超出范围的值。

这个有效

SELECT * 
FROM artists 
WHERE DOB IS NOT NULL
  AND SUBSTRING(DOB, 0, 5) > '1900' 
  AND convert(int, DATEPART(DAYOFYEAR, DOB)) = '100'

今天恰好是一年中的第100天

我不明白为什么,我正在使用SQL Server 2008。

该列设置为varchar(10)。我的日期可以追溯到1700年的

表中的日期格式为

1930-04-10
YYYY-MM-DD

我可以将两个查询放在同一个窗口中,一次突出显示并运行一个查询对同一个数据集。并得到上述结果。

2 个答案:

答案 0 :(得分:1)

在两个查询中,您正在检查两个条件:

SUBSTRING(DOB, 0, 5) > '1900'

CONVERT(INT, DATEPART(DAYOFYEAR, DOB)) = some integer;

DBMS决定首先检查哪一个。显然,在您的第一个查询中,DBMS首先检查第一个表达式,从而排除了一些无法用DOB转换的DATEPART。但是第二个查询首先检查第二个条件,并且尝试转换某个值失败。

我的建议:您最好的选择是更改表格并将DOB存储为DATETIME2而不是VARCHAR(10)

如果由于某种原因无法做到这一点,可以使用子查询(派生表)强制第一个条件优先于第二个条件:

select *
from artists
from
(
  select *
  from artists
  where substring(dob, 1, 4) > '1900'
) after_1900
where datepart(dayofyear, dob) = datepart(dayofyear, getdate());

这有效(希望如此),但并不完全正确。例如,DOB仍然可以包含无效日期,例如'2016-XY- ??'或者只是'2016-02-30'。在DATEPART表达式中,您将DOB视为DATETIME而不是select dob, name from ( select convert(datetime2, dob + ' 00:00:00', 120) as dob, name from artists from ( select dob, name from artists where dob like '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]' ) valid_data_strings ) converted where datepart(year, dob) > 1900 and datepart(dayofyear, dob) = datepart(dayofyear, getdate()); 。发生隐式转换,很容易失败。

这是一个查询,首先检查正确的日期格式,以及明确的字符串到日期转换:

Method, Classifier, Accuracy
M1, C1, 2.4
M1, C1, 2.3
M1, C1, 6.4
M1, C2, 0.4
M1, C2, 1.3
M1, C2, 6.8
M1, C3, 3.4
M1, C3, 2.7
M1, C3, 2.4
M2, C1, 0.4
M2, C1, 2.8
M2, C1, 3.4
M2, C2, 7.4
M2, C2, 2.3
M2, C2, 6.5
M2, C3, 1.4
M2, C3, 2.7
M2, C3, 7.4
M3, C1, 2.0
M3, C1, 1.3
M3, C1, 7.2
M3, C2, 8.4
M3, C2, 1.3
M3, C2, 9.8
M3, C3, 3.9
M3, C3, 3.7
M3, C3, 0.9

尽管如此,这并不能解决2月30日的问题。我不认为有一种简单的方法来检测有效的日期字符串,然后只考虑这些记录。可能,是的,但肯定有一些工作与所有闰年逻辑需要。

如上所述,改变表格设计要容易得多。

答案 1 :(得分:0)

答案很简单,但仍然很奇怪。

此声明不起作用

SELECT * FROM   artists WHERE  SUBSTRING(DOB, 0, 5) > '1900'
AND CONVERT(INT, DATEPART(DAYOFYEAR, DOB)) = (SELECT CONVERT(INT, datepart(DAYOFYEAR, getdate()))) 

这个确实

SELECT * FROM   artists WHERE  SUBSTRING(DOB, 0, 5) > '1900'
AND CONVERT(INT, DATEPART(DAYOFYEAR, DOB)) = (CONVERT(INT, datepart(DAYOFYEAR, getdate()))) 

通过从获取当前日期部分中删除Select,该语句会生动,这只能意味着添加“Select”(实际上没有区别),改变了优先顺序,这在一种错综复杂的方式。但我认为这是一个错误。