Xerratus
Happily stressed out, since 1974
Friday, January 11, 2008
<< SQL Random Sorting
Changing Visual Studios Default Debugging Browser >>
A better way to create a dynamic SQL stored procedure
This one has been plaguing me for years: What is the best way to create a dynamic stored procedure that allows null inputs to filter results? To solve this, over the years, I've tried a few things, below are just a couple:
Build a SELECT statement string together concatenating non-null values then execute the string.
Use IF statements to narrow down the type of filtering requested and run the pre-built SQL statement with the corresponding non-null values.
The problem with the above solutions is that neither rely on one solid select statement.
Today, while working on another request to come up with a dynamic stored procedure for a specific report a client wants, I had an epiphany. If I use isnull() in conjunction to with the actual value, I can get the desired results, no matter what input(s) are null -if any or all.
Here's the magic line that allows just that:
WHERE
D1.MarketID =
isnull
(@MarketID, D1.MarketID)
Now, we all know that isnull() returns the first non-null value. So, if @MarketID is null, then we just return the actual value of the row in question; D1.MarketId. For a fact, D1.MarketID will ALWAYS equal D1.MarketID. That's it!
So, if we create a sproc that takes in five different values (filters), all of which can be null, utilize the above isnull() trick, we can let out business layer decide which results to return simply by passing in an actual value or a
DBNull
.Value to the call. The stored procedure finally becomes dumb and all of the logic is finally in the hands of the business logic, where it should be, in a non-
kludgie
(pronounced "Hacked") way.
Here is a quick example:
CREATE PROC
Reporting_Impressions
@MarketID
int
= NULL,
@StartDate
datetime
= NULL,
@EndDate
datetime
= NULL,
@Page
varchar
(25) = NULL,
@LocationID
uniqueidentifier
= NULL
AS
SELECT
D1.LocationId, D1.LocationName, D1.MarketId, D1.MarketName,
D1.DisplayedOnPage, count(D1.DisplayedDate)
AS
TotalImpressions
FROM
PremiumMerchant_Displays
AS
D1
WITH
(NOLOCK)
INNER JOIN
PremiumMerchant_Displays
AS
D2
WITH
(NOLOCK)
ON
D1.LocationId = D2.LocationId
AND
D1.MarketId = D2.MarketId
AND
D1.DisplayedOnPage = D2.DisplayedOnPage
AND
D1.ImpressionId <> D2.ImpressionId
WHERE
D1.MarketID =
isnull
(@MarketID, D1.MarketID)
AND
D1.DisplayedOnPage =
isnull
(@Page, D1.DisplayedOnPage)
AND
D1.LocationId =
isnull
(@LocationID, D1.LocationId)
AND
D1.DisplayedDate >=
isnull
(@StartDate, D1.DisplayedDate)
AND
D1.DisplayedDate <=
isnull
(@EndDate, D1.DisplayedDate)
GROUP BY
D1.LocationId, D1.LocationName, D1.MarketId, D1.MarketName, D1.DisplayedOnPage
GO
And here are some various ways to call this procedure:
--Specific market id
EXEC
Reporting_Impressions 4,
NULL
,
NULL
,
NULL
,
NULL
--All, no filters
EXEC
Reporting_Impressions
NULL
,
NULL
,
NULL
,
NULL
,
NULL
--Date range
EXEC
Reporting_Impressions
NULL
,
'1/1/2008 7:00:00 AM'
,
'2/15/2008 11:00:00 AM'
,
NULL
,
NULL
--Specific page
EXEC
Reporting_Impressions
NULL
,
NULL
,
NULL
,
'Home'
,
NULL
--Specific Location
EXEC
Reporting_Impressions
NULL
,
NULL
,
NULL
,
NULL
,
'B40B82C9-A41A-49DA-8950-3CBFF4488AEA'
--Specific market id and page for a given date range
EXEC
Reporting_Impressions 4,
'1/1/2008 7:00:00 AM'
,
'2/15/2008 11:00:00 AM'
,
'Directory'
,
NULL
As you can see, there is only one stored procedure with many different results, all of which are dependent on the number of non-null inputs and snuggled within a nice, clean, single select statement.
Friday, January 11, 2008 @ 12:31 PM (-08:00) Pacific Standard Time
Comments (1)
tags:
Programming
|
SQL
admin: Edit | Remove
Thursday, April 24, 2008 10:30:35 AM (Pacific Standard Time, UTC-08:00)
This just tickled the pleasurable parts of my body.
(Dear fellow reader) Can you imagine a dynamic stored procedure, where you just selectively pass stuff, and what you don't pass, is always true (logically, disregarded), and what you do pass is used in the where (logically, filter)?
That's FANTASTIC! Thank you Xerratus.
David.Mater.Dei
Name
E-mail
Home page
Remember Me
Comment (Some html is allowed:
a@href@title, b, blockquote@cite, em, i, strike, strong, sub, super, u
) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.
Enter the code shown (prevents robots):
Live Comment Preview
Site Navigation
About Me
Calendar
Disclaimer
Site Search
Sponsored Links
Calendar
<
November 2008
>
Sun
Mon
Tue
Wed
Thu
Fri
Sat
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
6
Monthly Archives
August, 2008 (1)
July, 2008 (1)
March, 2008 (2)
January, 2008 (3)
December, 2007 (3)
October, 2007 (1)
September, 2007 (1)
August, 2007 (5)
July, 2007 (5)
June, 2007 (3)
April, 2007 (5)
February, 2007 (2)
January, 2007 (2)
December, 2006 (9)
November, 2006 (15)
October, 2006 (19)
September, 2006 (3)
August, 2006 (5)
July, 2006 (4)
June, 2006 (6)
May, 2006 (12)
April, 2006 (20)
March, 2006 (11)
February, 2006 (14)
January, 2006 (14)
December, 2005 (23)
November, 2005 (23)
October, 2005 (42)
September, 2005 (4)
Categories
Alert (14)
Community Server (2)
Daily Quote (1)
Did you know (7)
Dumb Searches (1)
Dumbass (15)
General (133)
Haiku (6)
Holiday (5)
Movie quote (8)
Paladin (4)
Paris (1)
Parody (1)
Photo (24)
Political (2)
Priceless (7)
Programming (35)
Pytheus (2)
Rant (23)
Screen capture (15)
SQL (3)
Technical (39)
Video (4)
Vista (8)
Visual Studio 2005 (2)
Wifey (33)
XP (1)
Feeds
RSS
Atom
Good Reading
Code Better
Coding Horror
Computer Zen
Daily WTF
Days Bush Has Left
Dooce
Fargg
Me-Nikk
Post Secret
Rory Blythe
TechCrunch
Sign In