Welcome to AspAdvice Sign in | Join | Help

Preventing dynamic SQL when using dynamic WHERE clause

I see surprisingly often people using dynamic SQL when their need is to filter data with WHERE clause, with varying fields fields used. Say I have a table


CREATE TABLE [dbo].[SAMPLETABLE](
 [id] [int] IDENTITY(1,1) NOT NULL,
 [somenumber] [int] NOT NULL,
 [sometext] [varchar](255) NULL,
 CONSTRAINT [PK_SAMPLETABLE] PRIMARY KEY CLUSTERED
(
 [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

CREATE NONCLUSTERED INDEX [IX_SAMPLETABLE] ON [dbo].[SAMPLETABLE]
(
 [somenumber] ASC,
 [sometext] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]


With data something like:

1 10 Test text 1
2 11 Test text 2
3 15 Test text 2
4 12 Test text 3
5 19 Something totally different


Ok. Let's say that my query would need to filter either with minimum somenumber or LIKE sometext or with both of them (let's forget the direct id restriction for the sake of the example). The needed SQL takes the minimum allowed somenumber in, and uses LIKE for sometext.

People very often would write the SQL in .NET code. The pseudo could be

Dim sql as String="select * from dbo.sampletable"
Dim sqlwhere As String=""

if somenumber <> 0 then
  sqlwhere &= "WHERE somenumber >= " & somenumber
end if

if sometext <> "" then

  If sqlwhere <> "" THEN
     sqlwhere &= " AND "
  else
   sqlwhere &= " WHERE "
  end if
 sqlwhere &= " sometext LIKE '%" & sometext & "%'"

end if

Then concatenate sql and sqlwhere if sqlwhere <> "" or they would build in in the stored proc and use sp_executesql or EXEC . Ofr course I didn't use parameters either in the previous pseudo, which is bad practise alone.

In fact, it's useful to know that you can build this "if something is passed then do something" directly into SQL. You can use basic boolean trick for that, by controlling the evaluation of OR operator. When either of the OR's two expressions are true, that's enough to evaluate the entire it as true. So, using certain defaults in stored proc for parameters and OR operator you can create a procedure (or just query) like this

CREATE PROCEDURE sampleTableSelect

 @somenumbermin int=NULL,
 @sometext varchar(255)=NULL
 
AS
BEGIN
 SELECT * FROM dbo.SAMPLETABLE
 WHERE (@somenumbermin IS NULL OR somenumber >= @somenumbermin)
 AND (@sometext IS NULL OR sometext LIKE '%' + @sometext + '%')
END

As you can see now: if @somenumbermin is not passed, it has NULL as default value and  the other side of the first OR isn't evaluated, meaning that part of the WHERE has no effect since it evaluates to true. Same applies for the @sometext. Basic idea is to check if passed parameter has default value , and when *not* then evaluate the other expression. Otherwise evaluate to true by default.

So this means you can execute the proc with following variations

> exec sampleTableSelect

1 10 Test text 1
2 11 Test text 2
4 12 Test text 3
3 15 Test text 2
5 19 Something totally different


> exec sampleTableSelect @sometext = 'text 2'

2 11 Test text 2
3 15 Test text 2

> exec sampleTableSelect @somenumbermin = 11

2 11 Test text 2
4 12 Test text 3
3 15 Test text 2
5 19 Something totally different

> exec sampleTableSelect @somenumbermin = 15,@sometext = 't'

3 15 Test text 2
5 19 Something totally different

And as you understand, from usage perspective be it directly running the proc or using it with SqlCommand, idea is to control it by passing the parameter. If you don't want the condition to apply, do not pass the related parameter. With this knowledge you could build queries so that you prepare for certain fields becoming queryable, and kind of "map" the likely variations in beforehand.

I'm not saying this is the correct way. It's just one way to do these things, but I like because it's explicit and keeps my procedure in control of the querying. So I prefer it.

Published Saturday, September 15, 2007 10:07 AM by joteke
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: Preventing dynamic SQL when using dynamic WHERE clause

thanks. Nice tip. Just used it and it saved quite a significant portion of thinking :).
Monday, February 09, 2009 3:09 PM by Kim

# re: Preventing dynamic SQL when using dynamic WHERE clause

Thank You!
Wednesday, May 20, 2009 11:32 AM by Roy

# re: Preventing dynamic SQL when using dynamic WHERE clause

Amazing trick! Saved me a lot of time ... thank you very much for sharing :)
Monday, June 22, 2009 6:29 AM by Hasan

# re: Preventing dynamic SQL when using dynamic WHERE clause

Hello, I came across http://www.sommarskog.se/dyn-search-2005.html#OR_ISNULL which states: "For maintainability this is a good choice, as there is no extra complexity. But this is a POOR solution for good PERFORMANCE. This procedure will never use any selective index, but you will get a query plan as if you had not supplied any search parameters at all." Please comment.
Friday, August 14, 2009 1:11 AM by dev

# re: Preventing dynamic SQL when using dynamic WHERE clause

Comment on what? There is no such thing as free lunch. There's always tradeoffs.

There is no doubt that Erland wouldn't be right but it's not the whole view, read on the article he says:

"A Useless Method?

So if this method always yields a table scan, it is worthless and should never be used? Not really so. Sometimes you can reasonably assume that the amount of data that you are to search will not exceed, say, 10.000 rows. As long as the response times are acceptable for the users, and there are no locking issues, there is no reason to make your programming more complex than necessary. And there are plenty of cases where you need to add an extra optional filter to an already efficient query on a non-indexed column, a case where this method is an excellent choice. I would go as far as to say that this technique should be a staple in your T-SQL programming. You just need to know when it's not the right thing to use.

"

Friday, August 14, 2009 4:04 AM by joteke

# re: Preventing dynamic SQL when using dynamic WHERE clause

And read the continued part about AND xx AND IS NOT NULL

Friday, August 14, 2009 4:13 AM by joteke

# Dynamic WHERE Clause with SQL Server Stored Procedure

Dynamic WHERE Clause with SQL Server Stored Procedure
Wednesday, October 21, 2009 9:01 AM by Brent Says...

# re: Preventing dynamic SQL when using dynamic WHERE clause

This is great, thanks.
Thursday, May 27, 2010 4:41 PM by cjspsx

Leave a Comment

(required) 
required 
(required) 
Enter the code you see below