简体   繁体   中英

Why this Query is returning different results for different date formats?

I have a table named book_data with batch_dt as column name of type varchar in sql server.

when I pass the query

SELECT DISTINCT batch FROM book_data 

it gives me the following results

  batch_dt
-------------
 2012-10-31
-------------
 2012-11-01
-------------
 2012-11-02
-------------
 2012-11-03
-------------
      .
      .
      .

Now what I am doing is getting the total count of records between two dates. Fairly a simple query.

SELECT COUNT(*) FROM book_data WHERE CONVERT(varchar(12),CONVERT(datetime,batch_dt),101) BETWEEN '11/02/2012' and '10/31/2012'

the result is 112

and just by changing the month from 02 to 2 the query gives me 218 results

SELECT COUNT(*) FROM book_data WHERE CONVERT(varchar(12),CONVERT(datetime,batch_dt),101) BETWEEN '11/2/2012' and '10/31/2012'

why this different behaviour?

Use CAST(batch_dt AS DATE) instead, and pass the date in a language neutral manner, in the format YYYYMMDD . This way it will be comared as a date not as a varchar :

SELECT COUNT(*) 
FROM book_data 
WHERE CAST(batch_dt AS DATE)
BETWEEN '20121102' and '20121130'

But, this is not safe, if there was any value in barch_dt in a wrong format, you will get a casting error. In this case you can add ISDATE(batch_dt) = 1 to ensure that it is a valid data time. But it is better to make this column of datatype DateTime .

Another thing to note: is that BETWEEN is asymmetric in SQL Server, meaning that BETWEEN '11/02/2012' and '10/31/2012' is evaluated as:

DATE >= '11/02/2012' 
AND
DATE <= '10/31/2012'

which will never be true, the reason it works for you is that the dates were be compared as strings not as a dates. But you have to keep it like BETWEEN the small value and the biggest value .

SELECT COUNT(*) 
FROM book_data 
WHERE CONVERT(DATETIME,batch_dt,101) BETWEEN '11/2/2012' and '10/31/2012'

This would be more appropriate

You compare string with BETWEEN . If you do so you need to make sure that you compare in the correct order => YYYYMMDD MM:SS would be a correct order.

If you can, add columns with type datetime and store real date time values in your database. If you can not do that you can split up the values and build a date value yourself. This is much slower then just use a CONVERT() or CAST() but you can make sure that it works even with wrong date-strings.

You can use PATINDEX(),LEFT(),RIGHT() keywords to get the values you need or you use a split() function (you can find many version google it, eg https://codereview.stackexchange.com/questions/15125/sql-server-split-function-optimized ). If you use the split function, then split by / and then get year, month, day from the positions.

But best would be still to have correct datetime values stored in your db.

You get this different behavior because you don't compare the dates but the strings/varchars.

For a Date (or DateTime ), 10/2/2012 is the same as 10/02/2012 .

But for string , these values are (of course) different. It's just as if you'd compare 'abcd' with 'ab0cd'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM