SQL, how to use Dynamic Condition logics? - sql

When you need Dynamic WHERE Clause I can use;
CREATE PROCEDURE [dbo].[sp_sel_Articles]
#articleId INT = NULL
, #title NVARCHAR(250) = NULL
, #accessLevelId INT = NULL
AS
BEGIN
SELECT *
FROM table_Articles Art
WHERE
(Art.ArticleId = #articleId OR #articleId IS NULL)
AND (Art.Title LIKE '%' + #title + '%' OR #title IS NULL)
AND (Art.AccessLevelId = #accessLevelId OR #accessLevelId IS NULL)
END
So, I am able to invoke this procedure -for example- ONLY by ArticleId
EXEC [sp_sel_Articles] #articleId = 3
But, sometimes I'll need to invoke by AccessLevelId and sometimes NOT by an EXACT VALUE. For example, I'll need MORE THAN the given accesslevelId or LESS THAN.
Current procedure can ONLY handle the EXACT value by using
Art.AccessLevelId = #accessLevelId
Could also be possible to give the CONDITION type as well as the value into the procedure? It may seem very odd in this example but please just bear with me:
CREATE PROCEDURE [dbo].[sp_sel_Articles]
#articleId INT = NULL
, #title NVARCHAR(250) = NULL
, #accessLevelId INT = NULL
, **#accessLevelIdCondition**
AS
BEGIN
SELECT *
FROM table_Articles Art
WHERE
(Art.ArticleId = #articleId OR #articleId IS NULL)
AND (Art.Title LIKE '%' + #title + '%' OR #title IS NULL)
AND (Art.AccessLevelId **#accessLevelIdCondition** #accessLevelId OR #accessLevelId IS NULL)
END
Perhaps an Function can be used, I don't know. Since, there will be at least 20 Procedure that will require this flexibility, I'll need a better, more global solution as much as possible rather than writing IF ELSE condition in every procedure.
Thanks in advance,

You'd probably need to use dynamic SQL to pass in the operator. Or you could pass in two values, e.g.
#MinAccessLevelID INT,
#MaxAccessLevelID INT
...
WHERE (
(#MinAccessLevelID IS NULL AND #MaxAccessLevelID IS NULL)
OR
(AccessLevelID >= #MinAccessLevelID AND AccessLevelID <= #MaxAccessLevelID)
)
When you want exact (e.g. only 3), just pass 3 into both values. When you want anything above 3, pass 20000000000 into the #Max param, or 0 if you want everything below 3.
But you'll find as these permutations get more complex, you are going to be better off just using dynamic SQL (and with optimize for ad hoc workloads set, this will be better for plan cache reuse and thwarting parameter sniffing as well).

Read this www.sommarskog.se/dynamic_sql.html before applying
CREATE PROCEDURE [dbo].[sp_sel_Articles]
#articleId INT = NULL
, #title NVARCHAR(250) = NULL
, #accessLevelId INT = NULL
, #accessLevelIdCondition varchar(100)
AS
BEGIN
DECLARE #SQL varchar(8000)
SET #SQL='
SELECT *
FROM table_Articles Art
WHERE
(Art.ArticleId = '+cast(#articleId as varchar(100))+' OR '+cast(#articleId as varchar(100))+'IS NULL)
AND (Art.Title LIKE ''%'' + #title + ''%'' OR #title IS NULL)
AND (Art.AccessLevelId '+#accessLevelIdCondition+ cast(#accessLevelId as varchar(100))+' OR '+cast(#accessLevelId as varchar(100))+' IS NULL) '
EXEC(#sql)
END

You can always make a dynamic query with just making a querystring
execute ('select count(*) from table' )
So with the params entered in your stored procedure, you can also form up a querystring which you can execute.

You could use a case statement - it can look a little funny if not formatted correctly but you can try something like:
SELECT Columns FROM SomeTable
WHERE 1 = CASE
WHEN #SomeOption = '<>' AND SomeValue >= #SomeMinParam AND SomeValue <= SomeMaxParam THEN 1
WHEN #SomeOption '=' AND SomeValue = #SomeMinParam THEN 1
ELSE 0
END
(though as Aaron pointed out - the <> you pass in doesn't really reflect the comparison operators in the statement - change this to something meaningful :))
in your case:
CREATE PROCEDURE [dbo].[sp_sel_Articles]
#articleId INT = NULL,
#title NVARCHAR(250) = NULL,
#MinaccessLevelId INT = NULL,
#MaxaccessLevelId INT = NULL,
#accessType varchar(5) = '<>'
AS
BEGIN
SELECT *
FROM table_Articles Art
WHERE
(Art.ArticleId = #articleId OR #articleId IS NULL)
AND (Art.Title LIKE '%' + #title + '%' OR #title IS NULL)
AND 1 = CASE
WHEN #accessType = '<>' AND (Art.AccessLevelId = #MinaccessLevelId OR #accessLevelId IS NULL) THEN 1
WHEN #accessType = '=' AND (Art.AccessLevelId >= #MinaccessLevelId OR Art.AccessLevelId <= #MaxaccessLevelId) THEN 1
ELSE 0
END
END
Maybe use a bit #CompareAccessLevelToMin instead of a varchar() for the #accessType param. Still has the trouble of not telling you what setting it to 'false' means though.

Related

Using SQL Server CASE statement in WHERE

I want to select records from a table in a stored procedure. Given parameters can be empty or a string including some keys separated by comma (1, 2, etc)
I want to manage that when a parameter is an empty string, "WHERE" ignore searching.
I'm using this code:
where (CASE when #PatientID <> 0 then ( dental.ID_Sick in (1,2)) else (1=1) end)
Something like that is working in W3School. I mean:
SELECT * FROM Customers
WHERE (case when 1=1 then (Country IN ('Germany', 'France', 'UK')) else 1=1 end);
What is the problem in my query that does not work? SQLServerManagementStudio is giving error on "IN" statement.
Solution:
The best way to handle such optional parameters is to use dynamic SQL and built the query on the fly. Something like....
CREATE PROCEDURE myProc
#Param1 VARCHAR(100) = NULL
,#Param2 VARCHAR(100) = NULL
,#Param3 VARCHAR(100) = NULL
,#ListParam VARCHAR(100) = NULL
--, etc etc...
AS
BEGIN
SET NOCOUNT ON;
Declare #Sql NVARCHAR(MAX);
SET #Sql = N' SELECT *
FROM TableName
WHERE 1 = 1 '
-- add in where clause only if a value was passed to parameter
+ CASE WHEN #Param1 IS NOT NULL THEN
N' AND SomeColumn = #Param1 ' ELSE N'' END
-- add in where clause a different variable
-- only if a value was passed to different parameter
+ CASE WHEN #Param2 IS NOT NULL THEN
N' AND SomeOtherColumn = #Param3 ' ELSE N'' END
-- List Parameter used with IN clause if a value is passed
+ CASE WHEN #ListParam IS NOT NULL THEN
N' AND SomeOtherColumn IN (
SELECT Split.a.value(''.'', ''VARCHAR(100)'') IDs
FROM (
SELECT Cast (''<X>''
+ Replace(#ListParam, '','', ''</X><X>'')
+ ''</X>'' AS XML) AS Data
) AS t CROSS APPLY Data.nodes (''/X'') AS Split(a) '
ELSE N'' END
Exec sp_executesql #sql
, N' #Param1 VARCHAR(100), #Param2 VARCHAR(100) ,#Param3 VARCHAR(100) ,#ListParam VARCHAR(100)'
, #Param1
, #Param2
,#Param3
, #ListParam
END
Problem with Other approach
There is a major issue with this other approach, you write your where clause something like...
WHERE ( ColumnName = #Parameter OR #Parameter IS NULL)
The Two major issues with this approach
1) you cannot force SQL Server to check evaluate an expression first like if #Parameter IS NULL, Sql Server might decide to evaluate first the expression ColumnName = #Parameterso you will have where clause being evaluated even if the variable value is null.
2) SQL Server does not do Short-Circuiting (Like C#), even if it decides to check the #Parameter IS NULL expression first and even if it evaluates to true, SQL Server still may go ahead and evaluating other expression in OR clause.
Therefore stick to Dynamic Sql for queries like this. and happy days.
SQL Server does not have a Bool datatype, so you can't assign or return the result of a comparison as a Bool as you would in other languages. A comparison can only be used with IF-statements or WHERE-clauses, or in the WHEN-part of a CASE...WHEN but not anywhere else.
Your specific example would become this:
SELECT * FROM Customers
WHERE 1=1 OR Country IN ('Germany', 'France', 'UK')
It would be better readable to rewrite your statement as follows:
WHERE #PatientID = 0
OR dental.ID_Sick in (1,2)
Referring to your actual question, I'd advise to read the linked question as provided by B House.
May be this straight way will work for you
IF (#PatientID <> 0)
BEGIN
SELECT * FROM Customers
WHERE Country IN ('Germany', 'France', 'UK')
END
try this:
WHERE 1=(CASE WHEN #PatientID <>0 AND dental.ID_Sick in (1,2) THEN 1
WHEN #PatientID =0 THEN 1
ELSE 0
END)

SQL OR CONDITION ON TWO DIFFERENT COLUMNS

I have two fields (#EmployeeId,#SSOId) out of which one value can come or both can come, but when i am applying OR condition it is not giving me correct output. What i am doing wrong ?
ALTER PROCEDURE [dbo].[usp_User_GetDetails] (
#UserId INT = NULL
,#ADSId NVARCHAR(32) = NULL
,#EmployeeId NVARCHAR(32) = NULL
,#SSOId NVARCHAR(32) = NULL
,#UserName NVARCHAR(100) = NULL
)
AS
*/
SET NOCOUNT ON;
BEGIN
SELECT [USER_ID] AS UserId
,[FIRST_NM] AS FirstName
,[LST_NM] AS LastName
,[FULL_NM] AS FullName
,[ADS_USER_ID] AS ADSId
,[SEG_ID] AS SegmentId
,[PHONE_NO] AS PhoneNo
,[FAX_NO] AS FaxNo
,[EMP_ID] AS EmployeeId
,[EMAIL_AD_TX] AS Email
,[SSO_ID] AS SSOId
,[SFDC_IN] AS IsSFDC
,[USER_SFDC_ID] AS UserSFDCId
,[MGR_SFDC_ID] AS ManagerSFDCId
,[ACT_IN] AS IsActive
,[SYS_USER_IN] AS IsSystemUser
,[PORFOLIO_OWN_IN] AS CanHavePortfolio
,[MGR_ID] AS ManagerId
,[LST_LOG_IN_TS] AS LastLoginDate
,[EMP_BAND_TX] AS Band
,[CREAT_TS] AS CreatedDate
,[CREAT_BY_USER_ID] AS CreatedBy
,[LST_UPDT_TS] AS UpdatedDate
,[LST_UPDT_BY_USER_ID] AS UpdatedBy
FROM [dbo].[USER] WITH (NOLOCK)
WHERE ([EMP_ID] = ISNULL(#EmployeeId, [EMP_ID])OR [SSO_ID] = ISNULL(#SSOId, [SSO_ID])
AND [ADS_USER_ID] = ISNULL(#ADSId, [ADS_USER_ID])
AND [USER_ID] = ISNULL(#UserId, [USER_ID])
AND [FULL_NM] LIKE CASE
WHEN #UserName IS NOT NULL
THEN '%' + #UserName + '%'
ELSE [FULL_NM]
END
END
I don't think the parentheses are balanced correctly. In any case, I would write this without the ISNULL():
WHERE ((#EmployeeId IS NULL OR EMP_ID = #EmployeeId) OR
(#SSOId IS NULL OR SSO_ID = #SSOId)
) AND
(#ADSId IS NULL OR ADS_USER_ID = #ADSId) AND
(#UserId IS NULL OR USER_ID = #UserId) AND
(#UserName IS NULL OR FULL_NM LIKE '%' + #UserName + '%')
I am guessing that the OR is for the first two conditions. This is where the parens don't seem to line up in the query in the question.
I prefer this construct for two reasons. First, it handles NULL values in the column values as well as the parameter values. And second -- because it is more general -- it is one of the standard two ways I use to handle optional parameters (the other is to use dynamic SQL which can make use of indexes).
Query seems to be okay .Are you passing DBNull from you C# code or empty text
WHERE (#EmployeeId IS NULL OR (EMP_ID = #EmployeeId))
AND (#SSOId IS NULL OR (SSO_ID = #SSOId))
AND [ADS_USER_ID] = ISNULL(#ADSId, [ADS_USER_ID])
AND [USER_ID] = ISNULL(#UserId, [USER_ID])
AND [FULL_NM] LIKE CASE
WHEN #UserName IS NOT NULL
THEN '%' + #UserName + '%'
ELSE [FULL_NM]
Used this script
WHERE EMP_ID = CASE WHEN ISNULL(#EmployeeId,0) > 0 THEN #EmployeeId ELSE EMP_ID END AND SSO_ID = CASE WHEN ISNULL(#SSOId,0) > 0 THEN #SSOId ELSE SSO_ID END

If Variable is Blank Then No Where Clause [Multiple]

This question is similar to this one
The only difference is I have 3 sql parameter which I set default value as null,
and if user provides any of these values, they should be included in where clause
here is the stored procedure:
create procedure [dbo].[SearchCareer]
#country int =null,
#state int =null,
#position int=null
as
begin
SELECT * FROM Careers where Location=#country and #state=#state and #position=#position
end
I have tried this approach:
begin
SELECT * FROM Careers where
((#position is null and Position is null)
or (Position = #position)) and
((#country is null and Location is null)
or (Location = #country)) and
((#state is null and StateID is null)
or (StateID = #state))
end
It works fine when user only enter position but wont work on other cases.
I know I can use IF , ELSE IF To check and then build my query, but I want to avoid that.
This is probably close to what you are thinking. If the table is large the performance of this type of approach can become problematic. I had to make some guesses here because you where doing things like checking to see if a variable was equal to the same variable.
SELECT * --You really should use only the columns you need instead of *
FROM Careers
where (Location = #country OR #country is null)
and ([state] = #state OR #state is null)
and (position = #position or #position is null)
This will do what you want:
SELECT * FROM Careers where case #country when is null THEN #country ELSE Location end=#country and case #state when is null THEN #state ELSE State end=#state and case #position when is null THEN #position ELSE Position end=#position
I assumed that two other fields are State and Position.

Simple SQL Query Help

I am building a query for a search in MS SQL 05
i have 4 things the user can select, and i want to use AND logic on it.
but i can't seem to get it to work when NULLs are being passed in.
this is what i have:
ALTER PROCEDURE [dbo].[sp_FindSource]
-- Add the parameters for the stored procedure here
#Code varchar(500),
#ssid varchar(50),
#serialNo varchar(50),
#category decimal(10,5)
as begin
SELECT *
FROM tblSource
WHERE Code IN (
SELECT Value
FROM funcListToTableInt(#Code,',')
)
and SSID LIKE '%' + #ssID + '%'
and serialNo LIKE '%' + #serialNo + '%'
and category = #category
end
NOTE: funcListToTableInt function, parses comma seporated values passed in (it works by itself, if i take the other where statements out)
The above search never returns anything, how can i ignore values if they are passed in black and only query the ones that have something in them? uuggh, it's been killing me.
You just have to wrap some OR #param IS NULL checks around your WHERE conditions:
ALTER PROCEDURE [dbo].[sp_FindSource]
-- Add the parameters for the stored procedure here
#Code varchar(500),
#ssid varchar(50),
#serialNo varchar(50),
#category decimal(10,5)
as begin
SELECT *
FROM tblSource
WHERE (Code IN (SELECT Value FROM funcListToTableInt(#Code,',')) OR #Code IS NULL)
AND (SiteSourceID LIKE '%' + #ssID + '%' OR #ssID IS NULL)
AND (serialNo LIKE '%' + #serialNo + '%' OR #serialNo IS NULL)
AND (category = #category OR #category IS NULL)
end
This looks very strange at first glance, since it is checking the parameters for IS NULL, but it works.
Try adding OR clauses for the nulls. SO for example change 'and category = #category' to 'and ((category = #category) or (category is null)).
Do this for all the items for whiuch you want to have a null imput essectially disable that particular test.
There are two ways:
Way 1, ADD OR Clause: It can kill the performance ....
SELECT *
FROM tblSource
WHERE (Code IN (
SELECT Value
FROM funcListToTableInt(#Code,',')
) OR #Code IS NULL)
and (SiteSourceID LIKE '%' + #ssID + '%' OR #SSID IS NULL)
and (serialNo LIKE '%' + #serialNo + '%' OR #serialNo IS NULL)
and (category = #category OR #category)
Way 2: Conditional logic
Considering you have 4 parameters and each may have a value or may not have a value, So you have 2*2*2*2 , 16 different cases. You can write something like:
IF (#SSID IS NULL AND #Code IS NULL AND #serialNo IS NULL AND #category IS NOT NULL) THEN
-- SEARCH only of category
ELSE IF (#SSID IS NULL AND #Code IS NULL AND #serialNo IS NOT NULL AND #category IS NULL) THEN
-- SEARCH only on Serial Number
.
.
.
.
.
As in SQL Server each If block cache its own plan, it will be more performing but based on parameter and there possible combinations this approach may or may not be desired ...

How do I create a stored procedure that will optionally search columns?

I'm working on an application for work that is going to query our employee database. The end users want the ability to search based on the standard name/department criteria, but they also want the flexibility to query for all people with the first name of "James" that works in the Health Department. The one thing I want to avoid is to simply have the stored procedure take a list of parameters and generate a SQL statement to execute, since that would open doors to SQL injection at an internal level.
Can this be done?
While the COALESCE trick is neat, my preferred method is:
CREATE PROCEDURE ps_Customers_SELECT_NameCityCountry
#Cus_Name varchar(30) = NULL
,#Cus_City varchar(30) = NULL
,#Cus_Country varchar(30) = NULL
,#Dept_ID int = NULL
,#Dept_ID_partial varchar(10) = NULL
AS
SELECT Cus_Name
,Cus_City
,Cus_Country
,Dept_ID
FROM Customers
WHERE (#Cus_Name IS NULL OR Cus_Name LIKE '%' + #Cus_Name + '%')
AND (#Cus_City IS NULL OR Cus_City LIKE '%' + #Cus_City + '%')
AND (#Cus_Country IS NULL OR Cus_Country LIKE '%' + #Cus_Country + '%')
AND (#Dept_ID IS NULL OR Dept_ID = #DeptID)
AND (#Dept_ID_partial IS NULL OR CONVERT(varchar, Dept_ID) LIKE '%' + #Dept_ID_partial + '%')
These kind of SPs can easily be code generated (and re-generated for table-changes).
You have a few options for handling numbers - depending if you want exact semantics or search semantics.
The most efficient way to implement this type of search is with a stored procedure. The statement shown here creates a procedure that accepts the required parameters. When a parameter value is not supplied it is set to NULL.
CREATE PROCEDURE ps_Customers_SELECT_NameCityCountry
#Cus_Name varchar(30) = NULL,
#Cus_City varchar(30) = NULL,
#Cus_Country varchar(30) =NULL
AS
SELECT Cus_Name,
Cus_City,
Cus_Country
FROM Customers
WHERE Cus_Name = COALESCE(#Cus_Name,Cus_Name) AND
Cus_City = COALESCE(#Cus_City,Cus_City) AND
Cus_Country = COALESCE(#Cus_Country,Cus_Country)
Taken from this page: http://www.sqlteam.com/article/implementing-a-dynamic-where-clause
I've done it before. It works well.
Erland Sommarskog's article Dynamic Search Conditions in T-SQL is a good reference on how to do this. Erland presents a number of strategies on how to do this without using dynamic SQL (just plain IF blocks, OR, COALESCE, etc) and even lists out the performance characteristics of each technique.
In case you have to bite the bullet and go through the Dynamic SQL path, you should also read Erland's Curse and Blessings of Dynamic SQL where he gives out some tips on how to properly write dynamic SQLs
It can be done, but usually these kitchen-sink procedures result in some poor query plans.
Having said all that, here is the tactic most commonly used for "optional" parameters. The normal approach is to treat NULL as "ommitted".
SELECT
E.EmployeeID,
E.LastName,
E.FirstName
WHERE
E.FirstName = COALESCE(#FirstName, E.FirstName) AND
E.LastName = COALESCE(#LastName, E.LastName) AND
E.DepartmentID = COALESCE(#DepartmentID, E.DepartmentID)
EDIT:
A far better approach would be parameterized queries.
Here is a blog post from one of the world's foremost authorities in this domain, Frans Bouma from LLBLGen Pro fame:
Stored Procedures vs. Dynamic Queries
Using the COALESCE method has a problem in that if your column has a NULL value, passing in a NULL search condition (meaning ignore the search condition) will not return the row in many databases.
For example, try the following code on SQL Server 2000:
CREATE TABLE dbo.Test_Coalesce (
my_id INT NOT NULL IDENTITY,
my_string VARCHAR(20) NULL )
GO
INSERT INTO dbo.Test_Coalesce (my_string) VALUES (NULL)
INSERT INTO dbo.Test_Coalesce (my_string) VALUES ('t')
INSERT INTO dbo.Test_Coalesce (my_string) VALUES ('x')
INSERT INTO dbo.Test_Coalesce (my_string) VALUES (NULL)
GO
DECLARE #my_string VARCHAR(20)
SET #my_string = NULL
SELECT * FROM dbo.Test_Coalesce WHERE my_string = COALESCE(#my_string, my_string)
GO
You will only get back two rows because in the rows where the column my_string is NULL you are effective getting:
my_string = COALESCE(#my_string, my_string) =>
my_string = COALESCE(NULL, my_string) =>
my_string = my_string =>
NULL = NULL
But of course, NULL does not equal NULL.
I try to stick with:
SELECT
my_id,
my_string
FROM
dbo.Test_Coalesce
WHERE
(#my_string IS NULL OR my_string = #my_string)
Of course, you can adjust that to use wild cards or whatever else you want to do.
Copying this from my blog post:
USE [AdventureWorks]
GO
CREATE PROCEDURE USP_GET_Contacts_DynSearch
(
-- Optional Filters for Dynamic Search
#ContactID INT = NULL,
#FirstName NVARCHAR(50) = NULL,
#LastName NVARCHAR(50) = NULL,
#EmailAddress NVARCHAR(50) = NULL,
#EmailPromotion INT = NULL,
#Phone NVARCHAR(25) = NULL
)
AS
BEGIN
SET NOCOUNT ON
DECLARE
#lContactID INT,
#lFirstName NVARCHAR(50),
#lLastName NVARCHAR(50),
#lEmailAddress NVARCHAR(50),
#lEmailPromotion INT,
#lPhone NVARCHAR(25)
SET #lContactID = #ContactID
SET #lFirstName = LTRIM(RTRIM(#FirstName))
SET #lLastName = LTRIM(RTRIM(#LastName))
SET #lEmailAddress = LTRIM(RTRIM(#EmailAddress))
SET #lEmailPromotion = #EmailPromotion
SET #lPhone = LTRIM(RTRIM(#Phone))
SELECT
ContactID,
Title,
FirstName,
MiddleName,
LastName,
Suffix,
EmailAddress,
EmailPromotion,
Phone
FROM [Person].[Contact]
WHERE
(#lContactID IS NULL OR ContactID = #lContactID)
AND (#lFirstName IS NULL OR FirstName LIKE '%' + #lFirstName + '%')
AND (#lLastName IS NULL OR LastName LIKE '%' + #lLastName + '%')
AND (#lEmailAddress IS NULL OR EmailAddress LIKE '%' + #lEmailAddress + '%')
AND (#lEmailPromotion IS NULL OR EmailPromotion = #lEmailPromotion)
AND (#lPhone IS NULL OR Phone = #lPhone)
ORDER BY ContactID
END
GO
We can use Generic #Search Parameter and pass any value to it for searching.
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: --
-- Create date:
-- Description: --
-- =============================================
CREATE PROCEDURE [dbo].[usp_StudentList]
#PageNumber INT = 1, -- Paging parameter
#PageSize INT = 10,-- Paging parameter
#Search VARCHAR(MAX) = NULL, --Generic Search Parameter
#OrderBy VARCHAR(MAX) = 'FirstName', --Default Column Name 'FirstName' for records ordering
#SortDir VARCHAR(MAX) = 'asc' --Default ordering 'asc' for records ordering
AS
BEGIN
SET NOCOUNT ON;
--Query required for paging, this query used to show total records
SELECT COUNT(StudentId) AS RecordsTotal FROM Student
SELECT Student.*,
--Query required for paging, this query used to show total records filtered
COUNT(StudentId) OVER (PARTITION BY 1) AS RecordsFiltered
FROM Student
WHERE
--Generic Search
-- Below is the column list to add in Generic Serach
(#Search IS NULL OR Student.FirstName LIKE '%'+ #Search +'%')
OR (#Search IS NULL OR Student.LastName LIKE '%'+ #Search +'%')
--Order BY
-- Below is the column list to allow sorting
ORDER BY
CASE WHEN #SortDir = 'asc' AND #OrderBy = 'FirstName' THEN Student.FirstName END,
CASE WHEN #SortDir = 'desc' AND #OrderBy = 'FirstName' THEN Student.FirstName END DESC,
CASE WHEN #SortDir = 'asc' AND #OrderBy = 'LastName' THEN Student.LastName END,
CASE WHEN #SortDir = 'desc' AND #OrderBy = 'LastName' THEN Student.LastName END DESC,
OFFSET #PageSize * (#PageNumber - 1) ROWS FETCH NEXT #PageSize ROWS ONLY;
END
My first thought was to write a query something like this...
SELECT EmpId, NameLast, NameMiddle, NameFirst, DepartmentName
FROM dbo.Employee
INNER JOIN dbo.Department ON dbo.Employee.DeptId = dbo.Department.Id
WHERE IdCrq IS NOT NULL
AND
(
#bitSearchFirstName = 0
OR
Employee.NameFirst = #vchFirstName
)
AND
(
#bitSearchMiddleName = 0
OR
Employee.NameMiddle = #vchMiddleName
)
AND
(
#bitSearchFirstName = 0
OR
Employee.NameLast = #vchLastName
)
AND
(
#bitSearchDepartment = 0
OR
Department.Id = #intDeptID
)
...which would then have the caller provide a bit flag if they want to search a particular field and then supply the value if they are to search for it, but I don't know if this is creating a sloppy WHERE clause or if I can get away with a CASE statement in the WHERE clause.
As you can see this particular code is in T-SQL, but I'll gladly look at some PL-SQL / MySQL code as well and adapt accordingly.
I would stick with the NULL/COALESCE method over AdHoc Queries, and then test to make sure you don't have performance problems.
If it turns out that you have slow running queries because it's doing a table scan when you're searching on columns that are indexed, you could always supplement the generic search stored procedure with additional specific ones that allow searching on these indexed fields. For instance, you could have a special SP that does searches by CustomerID, or Last/First Name.
Write a procedure to insert all employee data whose name start with A in table??