Conditional Where Arguments in SQL Server - sql

I have a table 'Asset' in database. This table has four fields (Id, Name, LocationId, CategoryId).
I want to make a stored procedure which will return the assets based on provided LocationId and CategoryId parameters.
I want to make Where clause optional with respect to LocationId i.e. If user passes LocationId as 0 then I dont want to put restriction on LocationId otherwise I need to put restriction on LocationId also. i.e If #LocationId is 0 then assets from all location ids should be returned.
How can I change following query to achieve this
select * from Asset where LocationId = #LocationId and CategoryId = #CategoryId
Any Help?

What you need to do is declare your variables as null at the beginning.
So #LocationID int = null
Then in your where clause you'll want to put something like
WHERE (LocationID = #LocationID or #LocationID IS NULL)
That way if you don't pass an ID, everything will be returned.
EDIT - So this works for you, just make the passing of the ID's optional instead of putting 0's in, you could of course do WHERE (LocationID = #LocationID or #LocationID = 0)
I just think the use of NULL's is much cleaner.
Full Query:
CREATE PROC
#LocationID int = 0,
#CategoryID int = 0
AS
SELECT *
FROM
Asset
WHERE
(LocationID = #LocationID or #LocationID = 0)
AND
(ActivityID = #ActivityID or #ActivtyID = 0)

You can use Case in your Where Clause
select * from Asset
where LocationId = Case When #LocationId=0 then LocationId else #LocationId end
and CategoryId = #CategoryId

Related

How to use cases inside of where clause?

I am attempting to choose one of the following paths. The user will either enter the customer name (#customer), the supplier name (#supplier), or the part number (#part). When they enter one of those I want to do a search in my table like customer_name=#customer if they choose customer and the same if they choose any of the others. Here is what I am trying.
CREATE PROCEDURE sp_edit_button
(
#customer nvarchar(200) = NULL,
#supplier nvarchar(200) = NULL,
#part nvarchar(100) = NULL
)
AS
BEGIN
SELECT *
FROM REC_INSP_LOG
WHERE (
CASE
WHEN #customer IS NOT NULL THEN customer_name = #customer
WHEN #supplier IS NOT NULL THEN supplier_name = #supplier
WHEN #part IS NOT NULL THEN part_num = #part
)
END
You can phrase this logic without a case expression:
WHERE (#customer IS NULL OR customer_name = #customer) AND
(#supplier IS NULL OR supplier_name = #supplier) AND
(#part IS NULL OR part_num = #part)
That said, the resulting query will not be able to take advantage of any indexes on a table. If that is something you want, then you will need to use conditional logic or dynamic SQL.
That indeed can't work, because you're treading the realm of dynamic SQL. Also note that your CASE is supposed to have an END at the end.
I would suggest taking a look at Gordon's answer or, if you're set on using a case, you could try this:
(CASE
WHEN (#customer IS NOT NULL AND customer_name = #customer)
OR #supplier IS NOT NULL AND supplier_name = #supplier
OR #part IS NOT NULL AND part_num = #part THEN 1
ELSE 0
END) = 1
But you still wouldn't be able to use the index properly.

Must declare the scalar variable "#LocationId"

SELECT *
FROM dbo.vwAlarmAssetGroupLocationReport
WHERE (LocationID = CAST(COALESCE(#LocationId, LocationId) AS UNIQUEIDENTIFIER)
OR TopLocationId = CAST(COALESCE(#LocationId, TopLocationId) AS UNIQUEIDENTIFIER))
AND DateCreated BETWEEN '2018-10-23 AND 2018-10-25'
AND AssetGroupId = '8E99BAFB-739A-E411-B54B-40F2E9985B7A'
ORDER BY DateCreated
keep getting this error message when I try to run my report in SQL Any ideas?
The problem is you have to define LocationId first.
Try add in front of your codeblock:
DECLARE #LocationID DATATYPE
SET #LOCATION ID = VALUE
You need to have a declaration for #locationID before running the main query like:
declare #LocationId int = 10;
SELECT * FROM dbo.vwAlarmAssetGroupLocationReport
WHERE (LocationID = CAST(COALESCE(#LocationId, LocationId) AS uniqueidentifier) OR TopLocationId = CAST(COALESCE(#LocationId, TopLocationId) AS uniqueidentifier))
AND DateCreated Between '2018-10-23' AND '2018-10-25'
AND AssetGroupId = '8E99BAFB-739A-E411-B54B-40F2E9985B7A'
ORDER BY DateCreated
ALso please notice that the AND keyword after BETWEEN keyword should not be in the quotes.

SQL Query data based on a variable

I have a simple query that I am trying to adapt to a new situation. For this situation, if the variable locationID=1 then I need all records, regardless of its locationID.
However, if it is not equal to 1, I need to only provide records that match that of the #locationID.
Here is my setup example:
DECLARE #locationID INT = 1; -- All Results Regardless of locationID
--DECLARE #locationID INT = 2; -- Only results that match this locationID (2)
--DECLARE #locationID INT = 3; -- Only results that match this locationID (3)
-- Temp Data
DECLARE #temp AS TABLE (color VARCHAR(10), locationID INT, name VARCHAR(20))
INSERT INTO #temp( color, locationID, name )VALUES ( 'Blue', 1, 'Test 1' )
INSERT INTO #temp( color, locationID, name ) VALUES ( 'Red', 2, 'Test 2' )
INSERT INTO #temp( color, locationID, name ) VALUES ( 'Red', 1, 'Test 3' )
INSERT INTO #temp( color, locationID, name ) VALUES ( 'Red', 2, 'Test 4' )
INSERT INTO #temp( color, locationID, name ) VALUES ( 'Red', 3, 'Test 5' )
-- Query
SELECT *
FROM #temp
WHERE
locationID = ...
I am trying to figure out if I need to use a CASE WHEN or some other method for this.
WHERE (locationID = #LocationId OR #locationID = 1)
Try this:
...WHERE (#LocationId = 1 AND 1=1)
OR (#LocationId <> 1 AND LocationId = #LocationId)
This seems devilishly simple, perhaps I am not understanding your question. If you want to query by a variable value, then just use the variable value:
DECLARE #LocationId INT = 1
SELECT *
FROM #temp
WHERE (#LocationId = 1 AND 1=1)
OR (#LocationId <> 1 AND LocationId = #LocationId)
A couple of other ideas. Since using a constant of 1 is not exactly intuitive or self-documenting, you could default that to NULL. And then say:
WHERE LocationID = COALESCE(#LocationID, LocationID);
If LocationID column is nullable, then instead you could use some token value that is at least slightly more self-documenting than 1, like -1 (since I don't think anyone looking at the code will immediately know that there isn't really a valid row where LocationID = 1):
WHERE LocationID = COALESCE(NULLIF(#LocationID, -1), LocationID);
This is susceptible to parameter sniffing, so you might want to add OPTION (RECOMPILE) if you find you are often switching between "all rows" and "very specific rows." You can also use dynamic SQL to optionally build the WHERE clause, assuming your real scenario uses a real table:
DECLARE #sql nvarchar(max) = N'SELECT ... FROM dbo.RealTable'
IF #LocationID <> 1 -- or IS NOT NULL or <> -1 or what have you
BEGIN
SET #sql += N' WHERE LocationID = #LocationID';
END
EXEC sys.sp_executesql #sql, N'#LocationID int', #LocationID;
This way you get a different plan when the parameter is included vs. when it is not, which doesn't really make the scan (where you need all rows) any better, but it guards against the case where you use a seek + lookup against all rows, which can be really bad. More often, it prevents you from getting the dreadful full table/index scan when you really could have used a seek. But which way that goes is completely dependent on which case is more likely the first time the query runs.
And even here you may want to use OPTION (RECOMPILE) at the end of #sql if the distribution of data across different LocationID values is (or might later become) heavily skewed.
I call this type of query "the kitchen sink," and have written about it here:
#BackToBasics : An Updated "Kitchen Sink" Example
So the variable should be 1 or the locationid?
You could use an IN for that.
... WHERE #LocationID IN (1, LocationID)
Example snippet:
declare #locationID int;
-- Test data using a table variable
declare #varTable table (id int identity(1,1) primary key, locationID int, name varchar(20), color varchar(10));
insert into #varTable (locationID, name, color) values
(1,'Test 1','Blue'),
(2,'Test 2','Red'),
(1,'Test 3','Red'),
(2,'Test 4','Red'),
(3,'Test 5','Red');
-- Returning all records
set #locationID = 1;
SELECT t.* FROM #varTable t WHERE #locationID IN (1, t.locationID);
-- Only returning those with locationID = 2
set #locationID = 2;
SELECT t.* FROM #varTable t WHERE #locationID IN (1, t.locationID);

Condition inside a Where clause in sql

I have a stored procedure. In that where condition, I want to select the not null value if there are any, else select the null value from the table. Anyone Kindly help me..
ALTER PROCEDURE SearchPromotionBYPromotionANDVehicleID
#PromotionCode VARCHAR(100)
,#TypeId INT
,#LocationId INT
,#ClientId INT
AS
BEGIN
SET NOCOUNT ON;
SELECT top 1 tp.PromotionID
,tp.PromotionCode
,tp.ClientID
,tp.StartDate
,tp.EndDate
,tp.VehicleTypeId
,tv.VehicleType
,tp.LocationId
FROM tblstudent tp
LEFT OUTER JOIN tblType tv ON tp.TypeId = tv.TypeId
WHERE tp.PromotionCode = #PromotionCode
AND
( ( #LocationId IS NOT NULL AND tp.LocationId = #LocationId ) OR (tp.LocationId IS NULL) OR (#LocationId IS NULL) or (tp.LocationId = 0 ) )
In this consider 2 records (r1 and r2) with same promotion code and one with all locations (that is location id 0) and another with a location ID. When the parameter #locationId have a value(consider the value equal to the value of the record r2) then it have to return the record 2. Else have to return r1.
WHERE tp.PromotionCode = #PromotionCode
AND (( #LocationId IS NOT NULL AND tp.LocationId = #LocationId ) OR tp.LocationId IS NULL)
This condition selects those values where #LocationId has a not null and not 0 value, And the value needs to match with tp.LocationId, Otherwise it returns those where tp.LocationId is null.
Is it the result what you want? If you want different, let me know

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