views:

206

answers:

5

In sql 2005, instead of building a query from dateparts year, month and date, is there an more succinct way of writing the where clause?

many thanks

+1  A: 

On SQL Server 2008, you would have a new DATE data type, which you could use to achieve this:

SELECT (list of fields)
FROM dbo.YourTable
WHERE dateValue BETWEEN 
   CAST(GETDATE() AS DATE) AND DATEADD(DAY, 1, CAST(GETDATE() AS DATE))

The CAST(GETDATE() AS DATE) casts the current date and time to a date-only value, e.g. return '2010-04-06' for April 6, 2010. Adding one day to that basically selects all datetime values of today.

In SQL Server 2005, there's no easy way to do this - the most elegant solution I found here is using numeric manipulation of the DATETIME to achieve the same result:

SELECT (list of fields)
FROM dbo.YourTable
WHERE dateValue BETWEEN 
   CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME) AND 
   DATEADD(DAY, 1, CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME))
marc_s
@marc_s - did you just delete your answer? freaked me out as I was trying to add a comment. If only I cud upgrade. Thanks for your help though much appreciated.
Chin
@Chin: yes, I had a silly answer first, deleted it, edited it, and undeleted it again :-)
marc_s
@marc_s: You sure have a deranged definition of the word "elegant", +1 :)
Jørn Schou-Rode
OK - I think PostMan's way to extracting only the date-part of a DATETIME is probably even more elegant ;-)
marc_s
@marc_s Thanks for this, How do you think this would perform in comparison with using 3 datepart clauses?
Chin
@Chin: if you have an index on the datetime field, it should be fairly OK in terms of performance. If you add the three parts Year,Month,Day to your table as computed fields and put an index on those three fields, it would be even better since it only needs to do an equality match (Year=2010,Month=04,Day=06) rather than a range query.
marc_s
Gotcha, this has been very insightful.
Chin
A: 

Something along the lines of this

CONVERT(date,tbldata.date)=CONVERT(date,getdate())

This assumes that the date column includes the time as well. If it does not then you can change it to

tbldata.date=CONVERT(date,getdate())

Kevin Ross
Sql Server 2005 has a `date` type? ;)
Jørn Schou-Rode
Turns out it does not. My current stack is SQL server 2008 its been a while since we upgraded and I assumed that 2005 had this feature.
Kevin Ross
+1  A: 

In SQL 2000 and SQL 2005 you can use a nice select statement to remove the time component from a DateTime, ie

SELECT DATEADD(dd, DATEDIFF(dd,0,GETDATE()), 0)

will return 6-Apr-2010 (well for today only).

So combined with marc_s's answer, you'd want

SELECT (list of fields)
FROM dbo.YourTable
WHERE dateValue BETWEEN DATEADD(dd, DATEDIFF(dd,0,'MY Date and Time, But I Only Want Date'), 0) 
AND DATEADD(dd, DATEDIFF(dd,0,'MY Date and Time, But I Only Want Date'), 1)

Edit: Changed to suit requirements, note the 1 in the second DateAdd (this adds the days it has been from the beginning to 1 (instead of 0), making it 7th Apr 2010 00:00:00) If you want 6th Apr 23:59:59 you take a second away from the second date

DATEADD(ss,-1,'My DateTime')

Final Call would become

DATEADD(ss,-1,DATEADD(dd, DATEDIFF(dd,0,'MY Date and Time, But I Only Want Date'), 1))

Ok that's alot of info at once! Hope it all makes sense :)

PostMan
I like your expression to get the date-only part better than my solution - but this select won't work, no?? If you have '2010-04-06 15:15:15' - how is comparing that to just the date part going to select that?? I think you need a `WHERE dateValue BETWEEN (today) AND (today+1 day)` kind of select to grab all those values today with any time-portion attached to them....
marc_s
Oh yes you are correct! My mistake
PostMan
If you want to completely destroy the indexes, you could use the DateAdd/DatePart on the DateValue, but that's a bad idea! (If you have good indexes :) )
PostMan
I have had times that are between 23:59:59.000 and 00:00:00.000 the next day eliminated from reports. so I would never use the "subtract one second method". It is better to keep the time at 00:00:000.000 and increment one day and just use "<" less than (yourColumn < FlooredEndRangeDateTime+1)
KM
A: 

Not good performance, but a solution:

SELECT * FROM tblDate WHERE CONVERT(VARCHAR, date, 112) = CONVERT(VARCHAR, GETDATE(), 112);

If it is a common query a computed column should be added with only year-month-day content.

Joakim Backman
you are correct, it will be slow, because no index will be used
KM
A: 

I've used a UDF to do this on datetime columns going back to SQL 2000.

CREATE FUNCTION [dbo].[GETDATENOTIME](@now datetime)
RETURNS smalldatetime
AS
BEGIN
    RETURN (CONVERT(smalldatetime, CONVERT(varchar, @now, 112)))
END

Usage:

DECLARE @date smalldatetime
SET @date = '4/1/10'
SELECT * FROM mytable WHERE dbo.GETDATENOTIME(date) = @date

Not the most efficient thing in the world (YMMV depending on your table) but it does the job. For tables where I know I'll be selecting based on date-without-time a lot, I'll have a column specifically for that with a default set to dbo.GETDATENOTIME(GETDATE()).

Dane
if you ever had an index on the "date" column, this will definitely not be able to use it and thus result in a table scan....
marc_s
Hence my disclaimer at the end. The OP asked for succinct syntax, so that's the answer I gave him.
Dane