tags:

views:

78

answers:

4

I've got a table with a "date" column, where a user input will be queried against (using stored procedure)..and results will be shown on a datagrid..

now a user can either enter a year, Year/month , Year/month/day.. (from drop down lists)

i know there r many possible ways to handle the different queries.. however i am trying to figure out which would be best practice:

Solution 1: having 3 different stored procedures , one for every case.

Solution 2: having 1 stored procedure, with 1 extra parameter as searchlvl , then using IF ELSE statements to decide what lvl of search should be applied.

Solution 3: having 1 stored procedure, and sending the datetime as 3 different parameters , then checking IF parameter is null , and using that to decide search lvl

Solution 4: your suggestions :)

NOTE: i know how to do partial search(using datepart), my question is about best practice among the 3 solutions i offered or any other solution offered in the answers.. Like which would be faster, lighter on database and such.. and which would be slower, heavier..

+1  A: 

You can use datepart to get the parts of you date you want to filter against as

declare @table table(
     DateVal DATETIME
)

INSERT INTO @table SELECT GETDATE()


DECLARE @Year INT,
     @Month INT,
     @Day INT

SELECT  @Year = 2009

SELECT  DATEPART(YY, DateVal) DateYear,
     DATEPART(MM, DateVal) DateMonth,
     DATEPART(DD, DateVal) DateDay,
     *
FROM @table
WHERE   (DATEPART(YY, DateVal) = @Year OR @Year IS NULL)
AND  (DATEPART(MM, DateVal) = @Month OR @Month IS NULL)
AND  (DATEPART(DD, DateVal) = @Day OR @Day IS NULL)
astander
I would go with one sp, 3 params and test as shouwn in my edited answer.
astander
yah my boss suggested a similar approach without the insert and such, so +1 "due to higher authorities influence" :D
Madi D.
Design for simplicity first, then when you see performance issues, then investigate those X-)
astander
+4  A: 

There are no levels.

When user selects year 2009, you search rows where date >= '2009.01.01 00:00' and < '2010.01.01 00:00'.

When he selects month 01 of year 2009 you search where date >= '2009.01.01 00:00' and < '2009.02.01 00:00'.

Of course you don't pass dates as strings, you should use CONVERT() or pass dates as DATETIME type. This is universal solution and will be fast, because it will use indexes. You can create stored procedure that takes two dates, it will allow to search by every date range, not only year/month/day.

LukLed
+1, but, are you suggesting doing the logic to convert the three doprdowns into a single date at the UI layer?
pipTheGeek
I am not suggesting anything on UI side. If he wants year/month/day dropdown, he can have them. I suggested filtering on db side.
LukLed
+1 for simplicity and speed (will wait alil for more answers)
Madi D.
as pipTheGeek indicated, i will end up needing to do some extra coding and calculations (and logic too) on the UI side..
Madi D.
+2  A: 

I'd do none of the above.

You should design you stored procedure to take three different ints, one for day, one for month and one for year. Leave the parameters nullable, but establish a convention so only meaningful parameter combinations are used. Then you construct a MINDATE and MAXDATE from the parameters.

Searching Datetime columns based on day/year/month requires a query like:

SELECT * FROM table WHERE date > MINDATE AND date < MAXDATE

which is pretty inefficient but not a definite problem.

Another approach (if the table is huge) would be to create an indexed view with year/month/day integer columns and search for exact matches there. To create such a view use DATEPART().

Johannes Rudolph
Searching on indexed date is inefficient? Isn't creating views and additional indexes on this views too much?
LukLed
Maybe it is overkill, but I guess SQLServer does similar optimization under the hood anyway when indexing a datetime column.
Johannes Rudolph
If it does, it propably uses it, so why do it once again? Why not just create index on datetime column?
LukLed
sorry, I wasn't clear enough about that one. Without further research I'd say KISS.
Johannes Rudolph
+1  A: 

I'd pass in year/month/date as separate parameters into one stored proc, say default of NULL.

Then, I'd use DATEADD to build up from/to datetimes and use that

...
SELECT
    @ToYear = ISNULL(@ToYear, DATEPART(year, GETDATE()), --or some base value, such as "1900"
    @ToMonth = ...

...
SELECT
    @DateTo = DATEADD(year, @ToYear, DATEADD(month, @ToMonth, DATEADD(day, @ToDay, 0), 0), 0)
....
SELECT * FROM myTable WHERE DateColumn >= @DateFrom AND DateColumn <= @DateTo

I would not use any functions on columns or conditional logic to switch between selects

gbn
i think "ISNULL" implicity does the IF logic.. so ur solution is to give a base-value to any NULL input, then do a range check (like lukeled suggested ).. wouldnt doing the null-> tobase value on the UI side before sending to DB better?
Madi D.
If does not matter if in DB or in client. I'd say DB because the stored proc should check/clean inputs anyway.
gbn
Agreed, I'd rather handle the logic in the SP, whether the client passes wrong dates, or forgets to pass dates, etc. Especially if multiple clients call the same procedure, the logic should be centralized not distributed.
Aaron Bertrand