I have searched and searched and tested and tested but I can't seem to find the answer.
Here's the setup. I have 4 parameters coming in that can either:
Match a column in the table
Parameter and table column are null
There's no match for the parameter but the associated table column has a null
I've tried:
PCN = ( CASE WHEN PCN = #group THEN #PCN
WHEN PCN IS NULL THEN NULL
END )
Handles, 2. Doesn't Handle, 3. Doesn't handle
( PCN= #PCN
or
PCN is null )
Doesn't handle, 2. Doesn't handle 3. doesn't handle
(IsNull(PCN,'none') = IsNull(#PCN,'none'))
Handles, 2. Handles, 3. Doesn't handle
Since the last one is the only one that's handling scenario 3, here's more details on that one.
DECLARE #bin varchar(6) = '123456'
, #PCN varchar(50) = 'abc'
, #Group varchar(50) = '0.0'
, #NDC = '01234567891'
select * from dbo.Insurance
WHERE (IsNull([Group],'none') = IsNull(#group,'none'))
and (IsNull(PCN,'none') = IsNull(#PCN,'none'))
and (IsNull(BIN,'none') = IsNull(#bin,'none'))
and (IsNull(NDC,'none') = IsNull(#NDC,'none') )
order by [Group] desc, PCN desc, BIN desc, NDC;
This query returns no results. My expectation is to return the row where Bin, Group and NDC match and PCN is NULL. Any insight you can provide would be much appreciated!
UPDATE:
RowId
BIN
PCN
Group
NDC
1
123456
abc
0.0
01234567891
2
123456
NULL
0.0
01234567891
Scenario 1 - PCN column = PCN variable , rowID 1 should be returned
Scenario 2 - PCN column & PCN variable are null, rowID 2 should be returned
Scenario 3 - PCN variable = 123, rowID 2 should be returned
Solution 1:
((Group IS NULL AND #group IS NULL) OR (Group IS NOT NULL AND #group IS NOT NULL AND Group = #group ))
and ...
Solution 2:
(Group= #group) OR (ISNULL(Group, #group) IS NULL)
and ...
you can have 3 OR's per parameter
select *
from dbo.Insurance
where ([Group] is null or #Group is null or [Group] = #Group)
and (PCN is null or #PCN is null or PCN = #PCN)
and (BIN is null or #bin is null or BIN = #bin)
and (NDC is null or #NDC is null or NDC = #NDC)
order by [Group] desc
, PCN desc
, BIN desc
, NDC;
WHERE
(colA = #a OR colA IS NULL)
The values match: accepts based on colA = #a
Both are NULL: accepts based on colA IS NULL
colA is NULL: also accepts based on colA IS NULL
But we also need to make sure no other cases pass:
There are values in both and they do not match: will not be accepted based on either half.
colA is not NULL and #a is NULL: also does not pass
I discussed the business requirements with our team again. Slight adjustment and just in case anyone runs into something similar in the future, here were are the final requirements and solve:
Parameter and column are the same
Parameter and column are both null
Column has a wildcard (*)
DECLARE #bin varchar(6) = '123456'
, #PCN varchar(50) = 'abc'
, #Group varchar(50) = '0.0'
, #NDC = '01234567891'
select * from dbo.Insurance
WHERE ((IsNull([Group],'none') = IsNull(#group,'none')) OR [Group] = '*')
and
((IsNull(PCN,'none') = IsNull(#PCN,'none')) OR PCN = '*')
and
((IsNull(BIN,'none') = IsNull(#bin,'none')) OR BIN = '*')
and
((IsNull(NDC9,'none') = IsNull(#NDC9,'none') ) OR NDC9 = '*')
order by [Group] desc, PCN desc, BIN desc, NDC;
Thank you everyone for your comments!
How can I append a string to a field based on a condition without having to repeat the same case statement multiple times in the SELECT?
For example.
CASE WHEN t1.location = A THEN '1111' ELSE '2222' + t1.telephone1,
CASE WHEN t1.location = A THEN '1111' ELSE '2222' + t1.telephone2
If I had to select 10 columns this way I would have to copy paste 10 times. I was thinking of a possible variable or CTE but that seems like I would have to repeat the case anyway?
You should be able to accomplish this with a CTE:
with t1_as_cte (myexpression,telephone1,telephone2)
as (
select CASE WHEN t1.location = A THEN '1111' ELSE '2222' end myexpression,
t1.telephone1,
t1.telephone2
from mytable t1
)
select myexpression + telephone1, myexpression + telephone2
from t1_as_cte
So if you have 10 phone number columns (for some reason) that you want to prefix all of them based on location, then use CROSS APPLY VALUES.
DROP TABLE IF EXISTS #Test;
CREATE TABLE #Test
(
TestID TINYINT IDENTITY PRIMARY KEY
,[Location] VARCHAR(1)
,Phone1 VARCHAR(15)
,Phone2 VARCHAR(15)
,Phone3 VARCHAR(15)
,Phone4 VARCHAR(15)
,Phone5 VARCHAR(15)
,Phone6 VARCHAR(15)
,Phone7 VARCHAR(15)
,Phone8 VARCHAR(15)
,Phone9 VARCHAR(15)
,Phone10 VARCHAR(15)
)
;
INSERT INTO #Test
([Location],Phone1,Phone2,Phone3,Phone4,Phone5,Phone6,Phone7,Phone8,Phone9,Phone10)
VALUES
('A','PhoneA','PhoneA','PhoneA','PhoneA','PhoneA','PhoneA','PhoneA','PhoneA','PhoneA','PhoneA')
,('B','PhoneB','PhoneB','PhoneB','PhoneB','PhoneB','PhoneB','PhoneB','PhoneB','PhoneB','PhoneB')
;
SELECT
TST.TestID
,Phone1 = CONCAT(PFX.Prefix,TST.Phone1)
,Phone2 = CONCAT(PFX.Prefix,TST.Phone2)
,Phone3 = CONCAT(PFX.Prefix,TST.Phone3)
,Phone4 = CONCAT(PFX.Prefix,TST.Phone4)
,Phone5 = CONCAT(PFX.Prefix,TST.Phone5)
,Phone6 = CONCAT(PFX.Prefix,TST.Phone6)
,Phone7 = CONCAT(PFX.Prefix,TST.Phone7)
,Phone8 = CONCAT(PFX.Prefix,TST.Phone8)
,Phone9 = CONCAT(PFX.Prefix,TST.Phone9)
,Phone10 = CONCAT(PFX.Prefix,TST.Phone10)
FROM #Test AS TST
CROSS APPLY
(
VALUES(CASE WHEN TST.[Location] = 'A' THEN '1111' ELSE '2222' END)
) AS PFX (Prefix)
You can use a function. Or you can use Cross Apply and Outer Apply
I have a procedure which receive a bit variable called #FL_FINALIZADA.
If it is null or false I want to restrict my select to show only the rows that contain null DT_FINALIZACAO values. Otherwise I want to show the rows containing not null DT_FINALIZACAO values.
Something like this:
SELECT
*
FROM
MyTable
WHERE
...
AND
(
OPE.DT_FINALIZACAO = (
CASE
WHEN (#FL_FINALIZADA <> 1)
THEN NULL
END
) OR
OPE.DT_FINALIZACAO IS NOT NULL
)
In this case I receive the message:
None of the result expressions in a
CASE specification can be NULL.
How can I achieve this?
Thanks in advance.
SELECT
*
FROM
MyTable
WHERE
(ISNULL(#FL_FINALIZADA, 0) = 0
AND
OPE.DT_FINALIZACAO IS NULL
)
OR
(#FL_FINALIZADA = 1
AND
OPE.DT_FINALIZACAO IS NOT NULL
)
Change the AND to be:
AND (((#FL_FINALIZADA <> 1) AND (OPE.DT_FINALIZACAO IS NULL)) OR ( (#FL_FINALIZADA = 1) AND (OPE.DT_FINALIZACAO IS NOT NULL)))
If the bit flag is 1 then DT_FINALIZACAO can't be null.
IF #FL_FINALIZADA IS NULL
SET #FL_FINALIZADA = 0
SELECT * FROM NewsletterSubscribers
WHERE
(#FL_FINALIZADA = 0 AND OPE.DT_FINALIZACAO IS NULL)
OR
(#FL_FINALIZADA = 1 AND OPE.DT_FINALIZACAO IS NOT NULL)
My detailed SQL is a little rusty, but have you tried using 0 insted of NULL? I would expect 0 to evaluate the same as NULL in that select
I tried searching around, but I couldn't find anything that would help me out.
I'm trying to do this in SQL:
declare #locationType varchar(50);
declare #locationID int;
SELECT column1, column2
FROM viewWhatever
WHERE
CASE #locationType
WHEN 'location' THEN account_location = #locationID
WHEN 'area' THEN xxx_location_area = #locationID
WHEN 'division' THEN xxx_location_division = #locationID
I know that I shouldn't have to put '= #locationID' at the end of each one, but I can't get the syntax even close to being correct. SQL keeps complaining about my '=' on the first WHEN line...
How can I do this?
declare #locationType varchar(50);
declare #locationID int;
SELECT column1, column2
FROM viewWhatever
WHERE
#locationID =
CASE #locationType
WHEN 'location' THEN account_location
WHEN 'area' THEN xxx_location_area
WHEN 'division' THEN xxx_location_division
END
without a case statement...
SELECT column1, column2
FROM viewWhatever
WHERE
(#locationType = 'location' AND account_location = #locationID)
OR
(#locationType = 'area' AND xxx_location_area = #locationID)
OR
(#locationType = 'division' AND xxx_location_division = #locationID)
Here you go.
SELECT
column1,
column2
FROM
viewWhatever
WHERE
CASE
WHEN #locationType = 'location' AND account_location = #locationID THEN 1
WHEN #locationType = 'area' AND xxx_location_area = #locationID THEN 1
WHEN #locationType = 'division' AND xxx_location_division = #locationID THEN 1
ELSE 0
END = 1
I'd say this is an indicator of a flawed table structure. Perhaps the different location types should be separated in different tables, enabling you to do much richer querying and also avoid having superfluous columns around.
If you're unable to change the structure, something like the below might work:
SELECT
*
FROM
Test
WHERE
Account_Location = (
CASE LocationType
WHEN 'location' THEN #locationID
ELSE Account_Location
END
)
AND
Account_Location_Area = (
CASE LocationType
WHEN 'area' THEN #locationID
ELSE Account_Location_Area
END
)
And so forth... We can't change the structure of the query on the fly, but we can override it by making the predicates equal themselves out.
EDIT: The above suggestions are of course much better, just ignore mine.
The problem with this is that when the SQL engine goes to evaluate the expression, it checks the FROM portion to pull the proper tables, and then the WHERE portion to provide some base criteria, so it cannot properly evaluate a dynamic condition on which column to check against.
You can use a WHERE clause when you're checking the WHERE criteria in the predicate, such as
WHERE account_location = CASE #locationType
WHEN 'business' THEN 45
WHEN 'area' THEN 52
END
so in your particular case, you're going to need put the query into a stored procedure or create three separate queries.
OR operator can be alternative of case when in where condition
ALTER PROCEDURE [dbo].[RPT_340bClinicDrugInventorySummary]
-- Add the parameters for the stored procedure here
#ClinicId BIGINT = 0,
#selecttype int,
#selectedValue varchar (50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT
drugstock_drugname.n_cur_bal,drugname.cdrugname,clinic.cclinicname
FROM drugstock_drugname
INNER JOIN drugname ON drugstock_drugname.drugnameid_FK = drugname.drugnameid_PK
INNER JOIN drugstock_drugndc ON drugname.drugnameid_PK = drugstock_drugndc.drugnameid_FK
INNER JOIN drugndc ON drugstock_drugndc.drugndcid_FK = drugndc.drugid_PK
LEFT JOIN clinic ON drugstock_drugname.clinicid_FK = clinic.clinicid_PK
WHERE (#ClinicId = 0 AND 1 = 1)
OR (#ClinicId != 0 AND drugstock_drugname.clinicid_FK = #ClinicId)
-- Alternative Case When You can use OR
AND ((#selecttype = 1 AND 1 = 1)
OR (#selecttype = 2 AND drugname.drugnameid_PK = #selectedValue)
OR (#selecttype = 3 AND drugndc.drugid_PK = #selectedValue)
OR (#selecttype = 4 AND drugname.cdrugclass = 'C2')
OR (#selecttype = 5 AND LEFT(drugname.cdrugclass, 1) = 'C'))
ORDER BY clinic.cclinicname, drugname.cdrugname
END
Please try this query.
Answer To above post:
select #msgID, account_id
from viewMailAccountsHeirachy
where
CASE #smartLocationType
WHEN 'store' THEN account_location
WHEN 'area' THEN xxx_location_area
WHEN 'division' THEN xxx_location_division
WHEN 'company' THEN xxx_location_company
END = #smartLocation
Try this:
WHERE (
#smartLocationType IS NULL
OR account_location = (
CASE
WHEN #smartLocationType IS NOT NULL
THEN #smartLocationType
ELSE account_location
END
)
)
CREATE PROCEDURE [dbo].[Temp_Proc_Select_City]
#StateId INT
AS
BEGIN
SELECT * FROM tbl_City
WHERE
#StateID = CASE WHEN ISNULL(#StateId,0) = 0 THEN 0 ELSE StateId END ORDER BY CityName
END
Try this query, it's very easy and useful: Its ready to execute!
USE tempdb
GO
IF NOT OBJECT_ID('Tempdb..Contacts') IS NULL
DROP TABLE Contacts
CREATE TABLE Contacts(ID INT, FirstName VARCHAR(100), LastName VARCHAR(100))
INSERT INTO Contacts (ID, FirstName, LastName)
SELECT 1, 'Omid', 'Karami'
UNION ALL
SELECT 2, 'Alen', 'Fars'
UNION ALL
SELECT 3, 'Sharon', 'b'
UNION ALL
SELECT 4, 'Poja', 'Kar'
UNION ALL
SELECT 5, 'Ryan', 'Lasr'
GO
DECLARE #FirstName VARCHAR(100)
SET #FirstName = 'Omid'
DECLARE #LastName VARCHAR(100)
SET #LastName = ''
SELECT FirstName, LastName
FROM Contacts
WHERE
FirstName = CASE
WHEN LEN(#FirstName) > 0 THEN #FirstName
ELSE FirstName
END
AND
LastName = CASE
WHEN LEN(#LastName) > 0 THEN #LastName
ELSE LastName
END
GO
In general you can manage case of different where conditions in this way
SELECT *
FROM viewWhatever
WHERE 1=(CASE <case column or variable>
WHEN '<value1>' THEN IIF(<where condition 1>,1,0)
WHEN '<value2>' THEN IIF(<where condition 2>,1,0)
ELSE IIF(<else condition>,1,0)
END)
Case Statement in SQL Server Example
Syntax
CASE [ expression ]
WHEN condition_1 THEN result_1
WHEN condition_2 THEN result_2
...
WHEN condition_n THEN result_n
ELSE result
END
Example
SELECT contact_id,
CASE website_id
WHEN 1 THEN 'TechOnTheNet.com'
WHEN 2 THEN 'CheckYourMath.com'
ELSE 'BigActivities.com'
END
FROM contacts;
OR
SELECT contact_id,
CASE
WHEN website_id = 1 THEN 'TechOnTheNet.com'
WHEN website_id = 2 THEN 'CheckYourMath.com'
ELSE 'BigActivities.com'
END
FROM contacts;
This worked for me.
CREATE TABLE PER_CAL ( CAL_YEAR INT, CAL_PER INT )
INSERT INTO PER_CAL( CAL_YEAR, CAL_PER ) VALUES ( 20,1 ), ( 20,2 ), ( 20,3 ), ( 20,4 ), ( 20,5 ), ( 20,6 ), ( 20,7 ), ( 20,8 ), ( 20,9 ), ( 20,10 ), ( 20,11 ), ( 20,12 ),
( 99,1 ), ( 99,2 ), ( 99,3 ), ( 99,4 ), ( 99,5 ), ( 99,6 ), ( 99,7 ), ( 99,8 ), ( 99,9 ), ( 99,10 ), ( 99,11 ), ( 99,12 )
The 4 digit century is determined by the rule, if the year is 50 or more, the century is 1900, otherwise 2000.
Given two 6 digit periods that mark the start and end period, like a quarter, return the rows that fall in that range.
-- 1st quarter of 2020
SELECT * FROM PER_CAL WHERE (( CASE WHEN CAL_YEAR > 50 THEN 1900 ELSE 2000 END + CAL_YEAR ) * 100 + CAL_PER ) BETWEEN 202001 AND 202003
-- 4th quarter of 1999
SELECT * FROM PER_CAL WHERE (( CASE WHEN CAL_YEAR > 50 THEN 1900 ELSE 2000 END + CAL_YEAR ) * 100 + CAL_PER ) BETWEEN 199910 AND 199912
Try this query. Its very easy to understand:
CREATE TABLE PersonsDetail(FirstName nvarchar(20), LastName nvarchar(20), GenderID int);
GO
INSERT INTO PersonsDetail VALUES(N'Gourav', N'Bhatia', 2),
(N'Ramesh', N'Kumar', 1),
(N'Ram', N'Lal', 2),
(N'Sunil', N'Kumar', 3),
(N'Sunny', N'Sehgal', 1),
(N'Malkeet', N'Shaoul', 3),
(N'Jassy', N'Sohal', 2);
GO
SELECT FirstName, LastName, Gender =
CASE GenderID
WHEN 1 THEN 'Male'
WHEN 2 THEN 'Female'
ELSE 'Unknown'
END
FROM PersonsDetail