Case statement in WHERE clause in SQL [duplicate] - sql

This question already has answers here:
SQL Switch/Case in 'where' clause
(14 answers)
Closed 8 years ago.
I have a table 'Route' with Id ,Name and Active columns. If Id = 0 I want to select all the Id's where Active = true.
If Id > 0 I want to select the data for particular Id where Active = true.
I tried with following Query. But not working. (here I passed 2 for a Id value.)
Can someone support me?
DECLARE #ID INT
SET #ID = 2
SELECT DISTINCT Id ,Name
FROM Route
WHERE
CASE WHEN #ID > 0
THEN Id = #ID AND Active= 1
ELSE
Active=1
END
Sample Data Attached.

No need to use case can be done using where clause only.
DECLARE #ID INT
SET #ID = 2
SELECT DISTINCT Id ,Name
FROM Route
WHERE Active=1 AND (Id = #Id OR #Id = 0);
Explanation:
WHERE
CASE WHEN #ID > 0
THEN Id = #ID AND Active= 1
ELSE
Active=1
a. if #ID > 0 then Id = #ID AND Active= 1
b. else Active=1
If you look into both cases closely, Active= 1 remains same in both cases so it can be taken safely to outside of the condition
Then the remaining part is, if #ID > 0 then Id = #ID i.e. select the row as per the parameter value when parameter has valid value, otherwise select all.
So, if you combine both it becomes
WHERE Active=1 AND (Id = #Id OR #Id = 0);

Related

how to apply isnull to variable?

I have table called sample with columns:
Id, Name, Dept, active
Query:
select Id
from Sample
where Dept = #Dept and active = 1
I want to fetch id from sample table name by passing deptment name whose is active. There can come situation where where I get 2 records. Two dept might be active. That's why I am taking top 1. Some time might not come any record.
That's why I used like this in stored procedure:
declare #TempId int
set top 1 #TempId = Id
from Sample
where Dept = #Dept and active = 1
if(#TempId is null)
begin
#TempId = 0
end
Can I use isnull in the above select instead of after which is suitable for both my conditions?
No. First it must be select, not set.
And if select returns no rows, #TempId will not be changed. See this simple example
declare #TempId int = 0;
select #TempId = null where 1=2;
select #TempId;
I would write following code:
DECLARE #TempId int =
COALESCE((SELECT TOP 1 Id FROM [Sample] WHERE Dept = #dept AND Active=1), 0)
If no rows are returned, NULL coalescing function is used.
At the time of selecting record, check for the NULL value, and select the record which is NOT NULL.
declare #TempId int
select top 1 #TempId = Id from Sample where Dept = #Dept and active = 1 and Id is not null

Case statement to switch the column being compared in sql where clause

I have a scenario where the column that I need to use in the where clause changes based on the value of a variable.
For example if #ID matches the TableID in Table1 then I'll use the code below
WHERE
Table1.TableID = CASE WHEN #ID= -1 THEN Table1.TableID ELSE #ID END
However, if the #ID matches the TableID of Table2 Then I need to use
WHERE
Table2.TableID = CASE WHEN #ID= -1 THEN Table2.TableID ELSE #ID END
How will I accomplish this? Will the OR clause work in this scenario?
Edit: Trying to provide more detail to make it more clear.
Sample data
Table 1
TableID
1
2
3
4
Table 2
TableID
10
11
12
13
If the #ID = -1 I want to see all the rows from both the tables.
If #ID = 1 then only show the first row from Table 1
If #ID = 10 then only show the last row from Table 2...and so on.
Couldn't you just do something like this.
where (#ID = Table1.TableID OR #ID = Table2.TableID)
If you are looking to see if #ID matches either of these tableID's than this seems like a much simpler way of doing it.
Try something like this....
WHERE
(#ID = -1 AND Table1.TableID = #ID)
OR
(#ID = -1 AND Table2.TableID = #ID)
It doesnt make sense the way you have asked the question, you have same value in both cases for #ID it could have been a simpler query something like this...
WHERE
(Table1.TableID = #ID)
OR
(Table2.TableID = #ID)
WHERE #ID IN (
Table1.TableID
,Table2.TableID
,-1
)
Try this minimal sum of products clause. Given the information available, this is the most I can tell you to do without blindly guessing at the structure of your query and DB:
WHERE
(Table1.TableID = #ID AND #ID <> -1) OR (Table2.TableID = #ID AND #ID <> -1)

Complex SQL selection query

I have a stored procedure which needs a different if condition to work properly.
The procedure has 2 parameter namely, #CategoryID and #ClassID, which basically come from a UI tree view functionality. #CategoryID corresponds to the parent nodes, while #ClassID corresponds to the child nodes.
Based upon the above parameters I need to make a selection(Column Code) from a table which has CategoryID and ClassID as columns.
Now there are 2 scenarios:
Scenario 1
#CategoryID:A
#ClassID:B (which is a child node of CategoryID A)
Result needed: Codes corresponding to only ClassID B, which is basically the intersection
Scenario 2
#CategoryID:A
#ClassID: C (which is not a child node for CategoryID A)
Result needed: Codes corresponding to the CategoryID A, as well as ClassID B, basically a union
The procedure which I wrote gives me correct answer for the second scenario, but the first scenario it fails. Below is my procedure:
ALTER PROCEDURE [dbo].[uspGetCodes]
#CategoryID varchar(50),
#ClassID varchar(50)
AS
BEGIN
BEGIN TRY
DECLARE #SQLQuery NVARCHAR(MAX)
SET #SQLQuery=N'SELECT Code FROM dbo.ClassToCategoryMapping WHERE '
IF (#CategoryID IS NULL OR #CategoryID='')
BEGIN
SET #SQLQuery=#SQLQuery + 'ClassId IN ('+#ClassID+')'
PRINT(#SQLQuery)
EXEC(#SQLQuery)
END
ELSE IF (#ClassID IS NULL OR #ClassID='')
BEGIN
SET #SQLQuery=#SQLQuery+'CategoryID IN ('+#CategoryID+')'
PRINT(#SQLQuery)
EXEC(#SQLQuery)
END
ELSE
BEGIN
SET #SQLQuery=#SQLQuery+'(CategoryID IN ('+#CategoryID+') OR ClassId IN ('+#ClassID+') )'
PRINT(#SQLQuery)
EXEC(#SQLQuery)
END
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS 'ErrorNumber', ERROR_MESSAGE() AS 'ErrorMessage', ERROR_SEVERITY() AS 'ErrorSeverity', ERROR_STATE() AS 'ErrorState', ERROR_LINE() AS 'ErrorLine'
RETURN ERROR_NUMBER()
END CATCH
END
The Last Else part actually does an 'OR', which gives me the union of the Codes for CategoryID's and ClassID's irrespective whether the given ClassID is a child of the given CategoryID or not.
My question over here would be, how to write the condition to achieve both the scenarios.
Latest Sample Data:
Scenario 1
#CategoryId=2,5, #ClassID=10 (Here 10 is the child while 2 is the parent, CategoryID 2 corresponds to ClassID's 10, 11, 12)
Expected Result: 10, 26, 27 (26 and 27 correspond to the CategoryID 5)
Scenario 2
#CategoryID=2, #ClassID=13,15 (13 and 15 is the child of a different parent, CategoryID 2 corresponds to ClassID's 10, 11 ,12)
Expected Result: 10, 11, 12, 13, 15
Data in Table dbo.ClasstoCategoryMapping will be somewhat as below:
CategoryID ClassID Code
2 10 200
2 11 201
2 12 202
5 26 501
5 27 502
6 15 601
6 16 602
6 17 603
7 20 701
7 21 702
7 22 703
I guess I have made my question quite clear, if no then, folks can ask me to edit it. I would be happy to do so. I urge the experts to assist me in this problem. Any pointers too will be quite appreciated.
Regards
Anurag
If I understand the question correctly, what you require in your result set is:
(all supplied classid) + (all classid for supplied categoryid with no matching supplied classid)
That would translate to the following:
CREATE PROCEDURE [dbo].[uspGetCodes]
(
#CategoryID varchar(50),
#ClassID varchar(50)
)
AS
BEGIN
SELECT COALESCE(CM.CategoryID, CM2.CategoryID) AS CategoryID,
COALESCE(CM.ClassID, CM2.ClassID) AS ClassID,
COALESCE(CM.Code, CM2.Code) AS Code
--Matched classIDs:
FROM dbo.udfSplitCommaSeparatedIntList(#ClassID) CLAS
JOIN dbo.ClassToCategoryMapping CM
ON CM.ClassId = CLAS.Value
--Unmatched CategoryIDs:
FULL
OUTER
JOIN dbo.udfSplitCommaSeparatedIntList(#CategoryID) CAT
ON CM.CategoryID = CAT.Value
LEFT
JOIN dbo.ClassToCategoryMapping CM2
ON CM.CategoryID IS NULL
AND CM2.CategoryID = CAT.Value
END
I have included Category, Class and Code in the result since its easier to see what's going on, however I guess you only really need code
This makes use of the following function to split the supplied comma separated strings:
CREATE FUNCTION [dbo].[udfSplitCommaSeparatedIntList]
(
#Values varchar(50)
)
RETURNS #Result TABLE
(
Value int
)
AS
BEGIN
DECLARE #LengthValues int
SELECT #LengthValues = COALESCE(LEN(#Values), 0)
IF (#LengthValues = 0)
RETURN
DECLARE #StartIndex int
SELECT #StartIndex = 1
DECLARE #CommaIndex int
SELECT #CommaIndex = CHARINDEX(',', #Values, #StartIndex)
DECLARE #Value varchar(50);
WHILE (#CommaIndex > 0)
BEGIN
SELECT #Value = SUBSTRING(#Values, #StartIndex, #CommaIndex - #StartIndex)
INSERT #Result VALUES (#Value)
SELECT #StartIndex = #CommaIndex + 1
SELECT #CommaIndex = CHARINDEX(',', #Values, #StartIndex)
END
SELECT #Value = SUBSTRING(#Values, #StartIndex, LEN(#Values) - #StartIndex + 1)
INSERT #Result VALUES (#Value)
RETURN
END
this is the sample query that can achieve your goal, is this what you want?
DECLARE #SAMPLE TABLE
(
ID INT IDENTITY(1,1),
CategoryId INT,
ClassID INT
)
INSERT INTO #sample
VALUES(2,10)
INSERT INTO #sample
VALUES(2,11)
INSERT INTO #sample
VALUES(2,12)
INSERT INTO #sample
VALUES(3,13)
DECLARE #CategoryID INT
DECLARE #ClassID Int
--Play around your parameter(s) here
SET #CategoryID = 2
SET #ClassID = 13
--Snenario 1
--#CategoryId=2, #ClassID=10 (Here 10 is the child while 2 is the parent, CategoryID 2 corresponds to ClassID's 10, 11, 12)
--Expected Result: 10
IF EXISTS(SELECT * FROM #SAMPLE WHERE CategoryId = #CategoryID AND ClassID = #ClassID)
SELECT ClassID FROM #SAMPLE WHERE CategoryId = #CategoryID AND ClassID = #ClassID
--Scenario 2
--#CategoryID=2, #ClassID=13 (13 is the child of a different parent, CategoryID 2 corresponds to ClassID's 10, 11 ,12)
--Expected Result: 10, 11, 12, 13
ELSE
SELECT ClassID FROM #SAMPLE WHERE ClassID = #ClassID OR CategoryId = #CategoryID
Try this
select * from yourtable
where CategoryId = #CategoryID and ClassID = #ClassID
union
select * from
(
select * from yourtable where ClassID = #ClassID
union
select * from yourtable where CategoryId = #CategoryID
) v
where not exists (select * from yourtable where CategoryId = #CategoryID and ClassID = #ClassID)
UPDATE FOR DELIMITED STRING
If you have a comma delimited string then it is best to use a CLR function to create the table, but you could use a SQL function. Examples of how to do this are easy to find with a Google search... but for reference here is one good article on the subject -> http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings I expect at some point there will be native support on most platforms.
Given that you have a function that returns a table of one column (named ID) of type int, or an empty table on a null input. Note: You may have to have the null return a table with one row containing an invalid value (a value that will never join), say -1.
The code is as simple as this:
SELECT Code
FROM ClassToCategoryMapping
LEFT JOIN MakeTableFromCVS(#CategoryID) AS CatTable
ON CatTable.ID = CategoryID
LEFT JOIN MakeTableFromCVS(#ClassID) AS ClassTable
ON ClassTable.ID = ClassID
WHERE
CASE
WHEN #CatgoryID IS NULL THEN -1 ELSE CatTable.ID
END = ISNULL(CatTable.ID,-1)
AND
CASE
WHEN #ClassID IS NULL THEN -1 ELSE ClassTable.ID
END = ISNULL(ClassTable.ID,-1)
AND
COALESCE(CatTable.ID,ClassTable.ID,-1) != -1
The logic is the same as below. Because the join will vary the values if it is not null we have to use a different trick. Here we use a marker value (in this case -1) to signal the null value. Any value that won't appear in the comma separated list will work as this marker value, remember it must be of the same type.
You don't need dynamic SQL here and you will find SQL server is better at optimizing if you don't use dynamic SQL. In fact, you don't even need an if statement If you can be sure the input is always null you can do this:
SELECT Code
FROM ClassToCategoryMapping
WHERE
How this works
This query checks for both CategoryID and ClassID columns match the incoming parameters but "ignores" the input when they are null by checking the column against itself. This is an handy SQL trick.
Note if you do need to check for empty strings then this will be almost as fast
DECLARE #myCatID varchar(max)
DECLARE #myClassID varchar(max)
SET #myCatID = #CategoryID
SET #myClassID = #ClassID
IF LTRIM(RTRIM(#CategoryID) = '' THEN SET #myCatID = NULL
IF LTRIM(RTRIM(#ClassID) = '' THEN SET #myClassID = NULL
SELECT Code
FROM ClassToCategoryMapping
WHERE CatgoryID = ISNULL(#myCatID,CategoryID)
AND ClassID = ISNULL(#myClassID,ClassID)
You can replace ISNULL() with COALESCE() if you want... they do the same thing in this case.

IF ELSE condition in SQL select

I want to do a if-else condition statement in SQL Server but am not sure how.
Inside the stored procedure I have the following parameters:
#MarketId nvarchar (10),
#RegionId nvarchar (10)
And the following statement:
select * from Interaction I
where
(#MarketId = 0 ) OR (I.MarketId = (SELECT Id FROM Market WHERE ExternalId = #MarketId))
What I want to do is to check the value of #MarketId
if #MarketId = 0
then I want the where condition for I.MarketId to get its Ids from elsewhere like
(SELECT ID FROM Market WHERE ExternalId = #RegionId)
otherwise, if its 1, then I just want to leave it as is and get the Id from #MarketId instead of #RegionId..
How should I go about this?
Thanks!
This should work:
SELECT *
FROM Interaction I
WHERE ( #MarketID = 0
AND EXISTS (SELECT 1 FROM Market
WHERE ExternalId = #RegionId AND Id = I.MarketID)
OR I.MarketID = #MarketID

How to check the status column in a table in SQL Server 2008?

I need a query to check the status column in a table, if all the records have status completed means I have to set #flag=0.
Table structure is:
ID |status |date
--------------------
1 |complete |01-01-2011
2 |complete |02-02-2011
3 |start |03-03-2011
As the 3rd record is start than I need to set #flag=1.
I mean, if all the records are complete than the flag should be 0 else 1
IF EXISTS (
SELECT *
FROM YourTable
WHERE COALESCE(status, 'start') <> 'complete'
)
SET #flag = 1;
ELSE SET #flag = 0;
You questions is not very clear, but I wonder if you might be looking for something like this:
declare #id int
set #id = 1
declare #flag int
select #flag = (case when status = 'complete' then 0 else 1 end) from [tablename] where id = #id
SET #flag = 0;
IF EXISTS(select 1 from YourTable y where y.[status] = 'start')
SET #flag = 1;