Conditional stored procedure with bool values - sql

I am trying to assemble a stored procedure to return a set of results.
On my page, I have three checkboxes and a searchbox.
Then in the stored procedure, I have this:
CREATE Procedure [dbo].[sp_Search]
#Bool1 bit = NULL,
#Bool2 bit = NULL,
#Bool3 bit = NULL,
#SearchTerm nvarchar(30)
As
Begin
Select
[CompanyID],
[CompanyName],
[Label],
[Bool1],[Bool2],[Bool3]
From [Contract Companies]
WHERE (CompanyName LIKE #SearchTerm OR [Label] LIKE #SearchTerm) AND
if(#Bool1 IS NOT NULL)
[Bool1] = 'True'
end
if(#Bool2 IS NOT NULL)
AND [Bool2] = 'True'
end
if(#Bool3 IS NOT NULL)
AND [Bool3] = 'True'
end
Something like that, with those three boolean values not true all the time, just when their checkbox will be checked.
How can I achieve that?
Thanks in advance, Laziale

You might try something like this:
create procedure [dbo].[sp_Search]
#Bool1 bit = null,
#Bool2 bit = null,
#Bool3 bit = null,
#SearchTerm nvarchar(30)
as
begin
select
CompanyID,
CompanyName,
Label,
Bool1,
Bool2,
Bool3
from Contract Companies
where (CompanyName like #SearchTerm or Label like #SearchTerm)
and (Bool1 = #Bool1 or #Bool1 is null)
and (Bool2 = #Bool2 or #Bool2 is null)
and (Bool3 = #Bool3 or #Bool3 is null)
end
This will get matching records for each bool when present, and all records otherwise.
It is noted that this may not be the best performing method of dynamically checking values, but they're bits here (often not indexed) and I think it fits very elegantly. There are alternatives discussed in that article.

Option with CASE expression
CREATE Procedure [dbo].[sp_Search]
#Bool1 bit = NULL,
#Bool2 bit = NULL,
#Bool3 bit = NULL,
#SearchTerm nvarchar(30)
As
Begin
Select
[CompanyID],
[CompanyName],
[Label],
[Bool1],[Bool2],[Bool3]
From [Contract Companies]
WHERE (CompanyName LIKE #SearchTerm OR [Label] LIKE #SearchTerm) AND
[Bool1] = CASE WHEN #Bool1 IS NOT NULL THEN 'True' ELSE [Bool1] END AND
[Bool2] = CASE WHEN #Bool2 IS NOT NULL THEN 'True' ELSE [Bool2] END AND
[Bool3] = CASE WHEN #Bool3 IS NOT NULL THEN 'True' ELSE [Bool3] END

Related

SQL filter with different colum base on condition

i want to filter table based on condition. like-
CREATE TABLE [dbo].[tblUserInfo](
[Id] [int] NOT NULL,
[TypeName] [int] NOT NULL,
[Value] [decimal](18, 2) NULL,
[Name] [nvarchar](250) NULL,
)
DECLARE #SearchText VARCHAR(250)='aa'
SELECT *FROM tblUserInfo
#SearchText has text then filter by TypeName column,
#SearchText is null then filter by Name column.
just for example.
How could i achieve that? Thanks in advance.
Your where clause should look like this:
where (#SearchText is null and Name = '.....') --filter by Name
or (#SearchText is not null and TypeName = '.....') --filter by TypeName
DECLARE #SearchText VARCHAR(250)='aa'
SELECT *FROM tblUserInfo
WHERE CASE WHEN #SearchText IS NULL THEN Name ELSE 'a' END = CASE WHEN #SearchText IS NULL THEN 'hehe' ELSE 'a' END
AND
(
CASE WHEN #SearchText IS NOT NULL THEN TypeName ELSE 1 END = CASE WHEN #SearchText IS NOT NULL THEN 2 ELSE 1 END
OR
CASE WHEN #SearchText IS NOT NULL THEN TypeName ELSE 1 END = CASE WHEN #SearchText IS NOT NULL THEN 3 ELSE 1 END
)
I tried like this, is there any better solution?

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

bit datatype in where condition

I have column "Status" of bit type in a table and in the declaration of parameters I have defaulted it to 0 and I have few other parameters coming in with defaulted to null
#FirstName varchar(20) = null,
#LastName varchar(20) = null,
#Status bit = 0
and my sql is something like
Select * from customers where
(ISNULL(#FirstName,'') ='' OR FirstName= #FirstName)
AND (ISNULL(#LastName,'') ='' OR LastName= #LastName)
AND (Status = #Status)
The situation is if only #FirstName value is sent from the code and the Value of the column "Status = 1" in the table and no value for #Status is sent, then since it #Status defaults to 0 no records get returned. How to deal with the bit type, in a situation where the parameter for the bit type is not sent and the value for it in the table is 1.
You can set the default value of your #status parameter to null, as you have with your other parameters.
#Status bit = null
You can rationalise your filter by doing this
where
isnull(#firstname, Firstname) = FirstName
and
isnull(#LastName, LastName) = LastName
and
isnull(#Status, Status) = Status
Both this, and your original query, won't return rows where the value in the database is null.

SQL, how to use Dynamic Condition logics?

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.

Null value column and NOT EXISTS T-sql

I'm trying to do the following:
IF NOT EXISTS (
SELECT *
FROM [tbl_web_company]
WHERE [name] = #name
AND [address1] = #address1
AND [address2] = #address2
AND [city] = #city
AND [province_id] = #province_id
AND [postal_code] = #postalcode
AND [contact_phone] = #phone
AND [contact_fax] = #fax
AND [deleted] = dbo.pvd_fn_getDeletedDate(#id, #active))
BEGIN
SELECT 'update'
END
ELSE
BEGIN
SELECT 'no update'
END
I'm basically trying to see if any of the columns have changed, but I'm having problems when #province_id and dbo.pvd_fn_getDeletedDate(#id, #active) are NULL in the database, and are both set as NULL.
Province ID is an INT - Nullable
Deleted is a Datetime - Nullable.
If the record in the database has NULL for both these values, then this will always select 'update'. Which is wrong as [province_id] and [deleted] are NULL.
Any suggestions how to handle NULLS in this case?
Can you use the ISNULL() function to set a default value?
SELECT *
FROM [tbl_web_company]
WHERE [name] = #name
AND [address1] = #address1
AND [address2] = #address2
AND [city] = #city
AND ISNULL([province_id],99999) = ISNULL(#province_id,99999)
AND [postal_code] = #postalcode
AND [contact_phone] = #phone
AND [contact_fax] = #fax
AND ISNULL([deleted], '1990-01-01') = ISNULL(dbo.pvd_fn_getDeletedDate(#id, #active), '1990-01-01')
BEGIN
SELECT 'update'
END
ELSE
BEGIN
SELECT 'no update'
END
Using ISNULL() prevents the optimizer from using indexes, so normally I'd advise against this, but the way this query is written, I'd be surprised if it's making use of an index anyway.
use
IS NULL
instead
= NULL
Use "IS NULL" instead:
SELECT 'Is null' WHERE NULL = NULL
woudn't return any rows, but:
SELECT 'Is null' WHERE NULL IS NULL
will...
A good reading about nulls here
As your values are coming from parameters and are not hard coded you can use the following:
...
AND ([province_id] IS NULL OR [province_id] = #province_id)
...
Use the same structure for your other NULLABLE fields.