SQL Server - Using CASE statement - sql

I have a SELECT statement with a WHERE clause that I want to dynamically change depending if a parameter is supplied or not.
I can't seem to understand how to use CASE statement in a WHERE clause but this is how I want it to look like using an IF statement.
DECLARE #Gender NVARCHAR(100) = NULL --this is an INPUT parameter and may or may not be NULL
DECLARE #Status NVARCHAR(100) = NULL --this is an INPUT parameter and may or may not be NULL
SELECT Name
FROM Person
WHERE
-- first WHERE clause
IF #Gender IS NULL
BEGIN
Gender IS NULL
END
ELSE
BEGIN
Gender = #Gender
END
AND
-- second WHERE clause
IF #Status IS NULL
BEGIN
Status IS NULL
END
ELSE
BEGIN
Status LIKE '%' + #Status + '%'
END
Is it possible to transform this code into a CASE statement?

I think you want:
select p.name
from person p
where ( (#gender is null and gender is null) or gender = #gender) and
( (#status is null and status is null) or status = #status);
Note that this does "null-matching". Often, people want to use NULL to select all records, not just the NULL ones. If that is what you intend, then:
select p.name
from person p
where ( #gender is null or gender = #gender) and
( #status is null or status = #status);
In either situation, case is not needed in the where. As a general rule, don't use case in where -- unless you really need it to control the order of evaluation of expressions.

You can do this:
SELECT Name
FROM Person
WHERE Gender = COALESCE(#gender, Gender)
AND (#Status is null or Status like '%' + #status + '%')

DECLARE #Gender NVARCHAR(100) = NULL --this is an INPUT parameter and may or may not be NULL
DECLARE #Status NVARCHAR(100) = NULL --this is an INPUT parameter and may or may not be NULL
SELECT Name
FROM Person
WHERE CASE WHEN #Gender IS NULL THEN 1
WHEN #Gender = ISNULL(Gender, '') THEN 1
ELSE 0
END = 1
AND CASE WHEN #Status IS NULL THEN 1
WHEN ISNULL(Status, '') LIKE '%' + #Status + '%' THEN 1
ELSE 0
END = 1

Related

Case Statement in Where Clause NULL case [duplicate]

This question already has answers here:
CASE in WHERE, SQL Server
(5 answers)
Closed 4 years ago.
I'm creating a query (to eventually be used in a stored procedure) with multiple variations on what criteria is entered in a form. Sometimes there can be an entry, sometimes not. Sometimes the data field has a value, sometimes it's NULL.
The fields in my form are NAME, SSN, and DRLICENSE.
DECLARE #name VARCHAR(30);
DECLARE #ssn VARCHAR(10);
DECLARE #drlic VARCHAR(10);
--(if for example, someone enters data in two of the fields like this...)
SET #name = 'SMITH'
SET #drlic = 'D'
(In stored procedure)
SET #name = #name + '%'
SET #ssn = #ssn + '%'
SET #drlic = #drlic + '%'
SELECT
NAME,
SSN,
DRLICENSE
FROM
TABLE
WHERE
NAME LIKE CASE WHEN LEN(#name) > 1 THEN #name ELSE NAME END
AND SSN LIKE CASE WHEN len(#ssn) > 1 THEN #ssn ELSE SSN END
AND DRLICENSE LIKE CASE WHEN LEN(#drlic) > 1 THEN #drlic ELSE DRLICENSE END
The idea behind my case statement is to check the variable for usage and perform a like if the name, ssn, or drlicense are partial entries.
My question is: how do I account for the case of NULL in the table column (i.e. SSN LIKE SSN does not work when SSN is NULL because SSN IS NULL needs to be there).
This isn't going to perform well, especially since you are using LIKE but parentheses are important here
where ((#name is null or name like '%' + #name + '%') or ( name is null))
and ((#ssn is null or ssn like '%' + #ssn + '%') or (ssn is null))
and ((#drlic is null or DRLICENSE like '%' + #drlic + '%') or (DRLICENSE is null))
This will return the NULL values in those columns regardless if a parameter is passed in or not. If you don't want the NULL then just remove the or ( name is null)) section from each line. I wasn't certain from your post.
if length(#foo) <= 1
set #foo = NULL
if length(#bar) <= 1
set #bar = NULL
...
WHERE (#foo is NULL or t.foo = #foo)
AND (#bar is NULL or t.bar like #bar)
OPTION (RECOMPILE)
This should do it:
WHERE (#name IS NULL OR name LIKE #name + '%')
AND (#ssn IS NULL OR ssn LIKE #ssn + '%')
AND (#drlic IS NULL OR drlicense LIKE #drlic + '%')
Note that if, for example, user searched for name = foo then it will return rows that match foo% and not rows that have NULL name.
You can inline adding the wild card to the parameter value and add your null checks inline as well. There is no need for a CASE statement either. For each of the parameter/column values the result returns true if the parameter is null or if the column value is null or if the column value starts with the passed in parameter value.
Where statement:
WHERE (Name IS NULL OR #name IS NULL OR Name LIKE #name + '%')
AND (SSN IS NULL OR #ssn IS NULL OR SSN LIKE #ssn + '%')
AND (DRLICENSE IS NULL OR #drlic IS NULL OR DRLICENSE LIKE #drlic + '%')
The key here is to not do any filtering if the incoming value to use is null or if the column value is null which I assume you do not want filtered on if it is null.
You could use ISNULL() it's very useful in cases like yours.
SELECT
NAME,
SSN,
DRLICENSE
FROM
TABLE
WHERE
ISNULL(NAME,0) LIKE ISNULL(ISNULL(#name, NAME),0)
AND ISNULL(SSN,0) LIKE ISNULL(ISNULL(#ssn, SSN),0)
AND ISNULL(DRLICENSE,0) LIKE ISNULL(ISNULL(#drlic, DRLICENSE),0)
This method will replace the NULL values with the column value if the column value is NULL then both will be set to 0 (which will be 0=0, which will always be true).
If I understand correctly, you want a NULL-safe equality. That is, you want NULL to match NULL and values to match values. So:
where (name = #name or (name is null and #name is null)) and
(ssn = #ssn or (ssn is null and #ssn is null)) and
(drlicense = #drlicense or (drlicense is null and #drlicense is null))
or, an intriguing variant:
where (select count(*)
from (select distinct *
from (values (name, 'name'), (#name, 'name'), (ssn, 'ssn'), (#ssn, 'ssn'), (drlicense, 'drlicense'), (#drlicense, 'drlicense')
v(val, which)
) x
) = 3
This is using group by semantics to combine NULL values.
Or, if you want some obfuscation:
where nullif(name, #name) is null and nullif(#name, name) is null and
nullif(ssn, #ssn) is null and nullif(#ssn, ssn) is null and
nullif(drlicense, #drlicense) is null and nullif(#drlicense, drlicense) is null

Get only updated columns by using OUTPUT Clause sql

I have following procedure to track column changes in the table.
ALTER PROCEDURE [UpdateAddress]
#id bigint=0,
#fullname varchar(200)='',
#address varchar(200)='',
#city varchar(200)='',
#state varchar(200)=''
AS
declare #desc varchar(500);
BEGIN
DECLARE #MyTableVar table(
fullname varchar(200) NULL,
address varchar(200) NULL ,
city varchar(200) NULL ,
state varchar(200) NULL );
BEGIN
UPDATE [Address]
SET
fullname=#fullname,
address=#address,
city=#city,
state=#state
OUTPUT deleted.fullname,
deleted.address,
deleted.city,
deleted.state
INTO #MyTableVar
WHERE [Id]=#id
here i will get all columns which are updated and not updated. So we need to compare both like deleted.fullname and inserted.fullname . So, if I have 20 columns in a table, and only 2 columns i updated. without comparing , is there any way to get only updated columns using output clause?
Example: I have 20 columns. in that only fullname and address i updated. so i should get Fullname,Address changed. without any comparison. Is there any sql built-in function like updated_column()?
You can use scalar expressions in the output. So, you could represent "no change" as, say, NULL:
OUTPUT (case when inserted.fullname <> deleted.fullname then deleted.fullname end),
(case when inserted.address <> deleted.address then deleted.address end),
(case when inserted.city <> deleted.city then deleted.city end),
(case when inserted.state <> deleted.state then deleted.state end)
This is unambiguous if the previous column values are never NULL.
You could also use the same idea to list together the columns that are changed:
OUTPUT deleted.fullname,
deleted.address,
deleted.city,
deleted.state,
((case when inserted.fullname <> deleted.fullname then 'fullname;' else '' end) +
(case when inserted.address <> deleted.address then 'address;' else '' end) +
(case when inserted.city <> deleted.city then 'city;' else '' end) +
(case when inserted.state <> deleted.state then 'state;' else '' end)
)
The expressions would be a bit more complicated to include NULL checks.

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

how to take all values from sql table column on condition?

I want to select all column values irrespective of NULL as column value
my problem is when i try to select values using IS NULL i'm getting such records also thise having NULL as a value :(
declare #status varchar(50)=NULL
declare #path varchar(50)= 'India'
select
*
from [vwMYDATA]
where
Path like '%' + #path + '%' and
(Status = #status or #status IS NULL)
vwMYDATA
path status
INDIA1 NULL
INDIA2 close
INDIA3 open
If i execute above query i'm getting all records whose status column has NULL value
expected is if no status value specified show all status records
path status
INDIA1 NULL
INDIA2 close
INDIA3 open
it is showing
path status
INDIA1 NULL
I'm passing these 2 parameters to stored procedure which is having this select statment.
please help me to filtered out and show all the records if status is not given as input
select
*
from [vwMYDATA]
where
Path like '%' + #path + '%' and
((#status IS NULL )OR (Status = #status or status IS NULL))
You need to change the WHERE clause to a Case statement if you want different actions based on whether the #status varchar is NULL.
Select *
From [vwMYDATA]
Where
Path Like Concat('%', #path, '%') And
1 = (
Case When #status Is Null Then 1
When Status = #status Then 1
Else 0
)
This might be inefficient and nonperformant. For performance, it would be better to have a completely different query that matches based on NULL or not, so that proper indexing can be applied.
If you're happy to always filter out records with a null status (which it seems you are) then this should work:
declare #status varchar(50)=NULL
declare #path varchar(50)= 'India'
select
*
from [vwMYDATA]
where
Path like '%' + #path + '%' and
(Status = #status or #status IS NULL)
AND Status IS NOT NULL
Just try remove or #status IS NULL condition
select
*
from [vwMYDATA]
where
Path like '%' + #path + '%' and
(Status = #status)
You need to change your condition like below:
declare #status varchar(50)=NULL
declare #path varchar(50)= 'India'
select
*
from [vwMYDATA]
where
Path like '%' + #path + '%' and
(#status IS NULL OR Status = #status)
you just need to change the place of condition because the conditions check from first, so now if the #status will be null, query don't check next condition.
Get NUll Value Records on Status
select * from vwMYDATA where status is null
Get Not NUll Value Records on Status
select * from vwMYDATA where status is not null

case statement in where clause condition in sql

I have a stored procedure like this:
ALTER PROCEDURE [dbo].[hr_SearchVacanciesAdmin]
#SearchText NVARCHAR(50) = NULL,
#CompanyName NVARCHAR(100) = NULL,
#DutyStationID INT = NULL,
#VacancyCategoryIDs VARCHAR(1000) = NULL,
#Status INT,
#Language INT = 1
BEGIN
SELECT * from table
where
deleted = 0
and status = #status
and catname = &searchtext
..
..
..
END
I want to add case statement in where condition so that if #status = 4 then delete = is not checked. I tried following but not working
WHERE
1 = CASE
WHEN #Status = 4
THEN #status
WHEN dbo.hr_Vacancies.Deleted = 0
--Search Criteria
AND dbo.hr_Vacancies.Status = #Status
THEN #Status
END
You don't need a CASE statement to acheive this functionality. The following will do fine:
SELECT *
from table
where (deleted = 0 OR #status=4)
and status = #status
and catname = #searchtext
Note also that your code refers to &searchtext in the where clause, but this should be #searchtext as per this answer (ie prefix with # not &).
#RB is correct you don't need a case for that but you can use a case with this trick, which is useful in other scenarios as well:
Where deleted = case #status when 4 then deleted else 0 end
You may use this construct for the SELECT query to start with:
Select * from table
WHERE
((1 = CASE WHEN #Status = 4 THEN 1 ELSE 0 END)
OR
dbo.hr_Vacancies.Deleted = 0)
AND
dbo.hr_Vacancies.Status = #Status