How to compare dates in SQL Server

I have an HTML form where I ask the user to select dates and then hit submit. Upon submitting, I am trying to fetch records between the selected dates using ColdFusion. My query looks like this:

SELECT  * 
FROM    user_activation_events
where   STATUS_CODE =1
AND     event_date >= #Dateformat(form.from_date, 'dd-mm-yyyy')#
AND     event_date <= #Dateformat(form.to_date, 'dd-mm-yyyy')#

But this does not work as the date is stored in the database in this format:

    yyyy-mm-dd hh:mm:ss

Can somebody please tell me how to do it?


Solution 1:

There are a couple of issues going on here. Any form field that ends in _date is a form validation criteria. So the form field needs to be renamed todate and fromdate. Next it is good that you are trying to sanitize the input. cfqueryparam is used to do that. Last but not least, between is cleaner SQL Your query should look a little like:

<cfif isDate(form.fromDate) AND isDate(form.toDate)>

    <cfquery name="qryUser_Activation_Events">
    SELECT * 
    FROM   user_activation_events
    WHERE  STATUS_CODE =1
    AND    event_date BETWEEN <cfqueryparam cfsqltype="CF_SQL_date" value="#form.fromDate#">
        AND DATEADD(d, 1, <cfqueryparam cfsqltype="CF_SQL_date" value="#form.toDate#">)
    ORDER BY ...
    </cfquery>

<cfelse>  
    <!--- Error handling goes here --->
</cfif>

Solution 2:

As suggested in the comments, a more flexible way to filter the dates is using this approach. It works regardless of whether the column contains dates only or dates and times and will not interfere with the database's use of indexes (as using date functions may).

    WHERE  TheDateColumn >= TheStartDateAtMidnight         
    AND    TheDateColumn < TheDayAfterEndDateAtMidnight   

For example, if you wanted to return all records dated any time between 12/3 and 12/4/2012:

<!--- omitted date validation for brevity ---> 
<cfset form.from_date = "12/03/2012">
<cfset form.to_date   = "12/04/2012">

<cfquery name="getEvents" datasource="#dsn#">
    SELECT  event_date
    FROM    user_activation_events 
    WHERE   event_date >= <cfqueryparam value="#form.from_date#" cfsqltype="cf_sql_date">
    AND     event_date < <cfqueryparam value="#dateAdd('d', 1, form.to_date)#" cfsqltype="cf_sql_date">
    AND     status_code = 1 
</cfquery>


Sample Data

    2012-12-02 23:59:59.000
    2012-12-03 00:00:00.000
    2012-12-03 07:34:18.000
    2012-12-04 13:34:18.000
    2012-12-04 23:59:59.000
    2012-12-05 00:00:00.000

Results:

    1 | 2012-12-03 00:00:00.0  
    2 | 2012-12-03 07:34:18.0  
    3 | 2012-12-04 13:34:18.0  
    4 | 2012-12-04 23:59:59.0  



Note about dates:

But this does not work as the date is stored in the database in this format: yyyy-mm-dd hh:mm:ss

It really has nothing to do with format. Datetime values are not stored the way you see them on screen. The yyyy-mm-dd hh:mm:ss is a user friendly string presented by whatever IDE you are using, and it can vary. Normally, datetime values are actually stored as numbers. The number typically represents an offset from some base date or epoch. In CF/java it is the number milliseconds since the unix epoch. So while your IDE may show you a human friendly date string like yyyy-mm-dd hh:mm:ss, internally it is just a number.

Think of date queries as like any numeric comparison. If the query does not return all of the records you are expecting, it is usually because one of the numbers you are passing in is too large or small.

 WHERE Col >= 1354510800000   // java.util.Date => {ts '2012-12-03 00:00:00'}
 AND   Col <= 1354683600000   // java.util.Date => {ts '2012-12-05 00:00:00'}