Question

I need to write a Search Query (Stored Procedure) wherein the number of input parameters will be more than 15. User can pass single parameter value or combinations of parameters.

What would be the best approach

  1. Static Approach as below:

    DECLARE @FirstName VARCHAR(50) = 'XYZ' ,
    @LastName VARCHAR(50) = 'ABC' ,
    @MiddleName VARCHAR(50) = '999-9999%'';  Select 1 as Abc where 1 like ''%1'
    SELECT *
    FROM   [Person].[Person]
    WHERE  FirstName LIKE '%' + @FirstName + '%'
        OR LastName LIKE '%' + @LastName + '%'
        OR MiddleName LIKE '%' + @MiddleName + '%'
    
  2. Dynamic SQL Approach as below:

    DECLARE @FirstName VARCHAR(50) = 'XYZ', @LastName VARCHAR(50) = 'ABC', @MiddleName VARCHAR(50) = '999-9999%'
    
    DECLARE @select VARCHAR(5000) = 'Select * from [Person].[Person] '
    DECLARE @WhereClause VARCHAR(5000) = 'Where'
    IF (@FirstName IS NOT NULL OR @FirstName <> '')
        SET @WhereClause = @WhereClause + ' FirstName Like ''%' + @FirstName + '%'''
    
    IF (@LastName IS NOT NULL OR @LastName<> '') 
        IF (@WhereClause <> 'Where')
            SET @WhereClause = @WhereClause + ' OR LastName Like ''%' + @LastName+ '%'''
        ELSE
            SET @WhereClause = @WhereClause + ' LastName Like ''%' + @LastName+ '%'''
    
    IF (@MiddleName IS NOT NULL OR @MiddleName <> '') 
        IF (@WhereClause <> 'Where')
            SET @WhereClause = @WhereClause + ' OR MiddleName Like ''%' + @MiddleName + '%'''
        ELSE
            SET @WhereClause = @WhereClause + ' MiddleNameLike ''%' + @MiddleName + '%'''
    

    exec (@select + @WhereClause)

Now the Issues:

With approach 1 I have to include every single parameter within the WHERE clause. Which I think would be bit of performance degrade and everytime even though the value for a parameter is not supplied it will still search in relevant column.

With approach 2 I think it is likely to SQL Injection. Example: if the parameter values in case 2 are passed as

DECLARE @FirstName VARCHAR(50) = 'XYZ', @LastName VARCHAR(50) = 'ABC', @MiddleName VARCHAR(50) = '999-9999%'';  Select 1 as Abc where 1 like ''%1';

the resulting SQL Query which will execute will be

Select * from [Person].[Person] Where FirstName Like '%XYZ%' OR LastName Like '%ABC%' OR MiddleName Like '%999-9999%';  Select 1 as Abc where 1 like '%1%'

which is not good.

So what is the best way to code this with best performance.

Was it helpful?

Solution

I prefer approach #1.

  • Easier to maintain the code in #1.
  • In most cases #1 will be faster than #2.
  • Handling quotes inside quotes is a headache. ' OR LastName Like ''%' + @LastName+ '%'''
  • Dynamic sql is harder to debug. May not be in this case.
  • When your requirement changes your dynamic code will get messier and messier.
  • Query plan won't be cached in #2.
  • SQL Injection as you indicated.

OTHER TIPS

Dynamic SQL will normally take a performance hit because it can't cache the query plan inside SQL server.

I personally prefer Approach 1 too but if it's not done right then it can be very slow, particularly since open ended LIKE statements such as var LIKE "%text%" can take huge quantities of time to execute.

My suggestion would be to have the input parameters have default values of null and then structure your WHERE clause as follows

SELECT *
FROM table t
WHERE t.column1 = ISNULL(@param1, t.column1)
AND t.column2 = ISNULL(@param2, t.column2)

This means that in the instance where the parameter is not provided it simply returns all other matching results.

You may have to do something clever for date range matching however by using the minimum and maximum possible date / time where the parameter is NULL to ensure that all records should be in the range.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top