CASE in SELECT WHERE statement for stored procedure? - sql

I need to filter a table based on ManufacturerID in a stored procedure BUT when a null ManufacturerID is passed in I need all orders.
Can I do this in the WHERE statement so I don;t have to have the entire query written twice in my SP?

WHERE
#param IS NULL OR field = #param
But note, this gets very inefficient if you scale it up to search multiple columns. (See http://www.sommarskog.se/dyn-search.html)
Example of inefficient scaled up version...
WHERE
(#param1 IS NULL OR field1 = #param1)
AND (#param2 IS NULL OR field2 = #param2)
AND (#param3 IS NULL OR field3 = #param3)

You can do this:
where t.ManufacturerID = #ManufacturerIDParam OR #ManufacturerIDParam is null

Try:
WHERE table.field = coalesce(#param, table.field)

This can also lead to parameter sniffing issues. If possible, might want to clean up the nulls first instead?

Related

Ignore other results if a resultset has been found

To start, take this snippet as an example:
SELECT *
FROM StatsVehicle
WHERE ((ReferenceMakeId = #referenceMakeId)
OR #referenceMakeId IS NULL)
This will fetch and filter the records if the variable #referenceMakeId is not null, and if it is null, will fetch all the records. In other words, it is taking the first one into consideration if #referenceMakeId is not null.
I would like to add a further restriction to this, how can I achieve this?
For instance
(ReferenceModelId = #referenceModeleId) OR
(
(ReferenceMakeId = #referenceMakeId) OR
(#referenceMakeId IS NULL)
)
If #referenceModelId is not null, it will only need to filter by ReferenceModelId, and ignore the other statements inside it. If I actually do this as such, it returns all the records. Is there anything that can be done to achieve such a thing?
Maybe something like this?
SELECT * FROM StatsVehicle WHERE
(
-- Removed the following, as it's not clear if this is beneficial
-- (#referenceModeleId IS NOT NULL) AND
(ReferenceModelId = #referenceModeleId)
) OR
(#referenceModeleId IS NULL AND
(
(ReferenceMakeId = #referenceMakeId) OR
(#referenceMakeId IS NULL)
)
)
This should do the trick.
SELECT * FROM StatsVehicle
WHERE ReferenceModelId = #referenceModeleId OR
(
#referenceModeleId IS NULL AND
(
#referenceMakeId IS NULL OR
ReferenceMakeId = #referenceMakeId
)
)
However, you should note that this types of queries (known as catch-all queries) tend to be less efficient then writing a single query for every case.
This is due to the fact that SQL Server will cache the first query plan that might not be optimal for other parameters.
You might want to consider using the OPTION (RECOMPILE) query hint, or braking down the stored procedure to pieces that will each handle the specific conditions (i.e one select for null variables, one select for non-null).
For more information, read this article.
If #referenceModelId is not null, it will only need to filter by
ReferenceModelId, and ignore the other statements inside it. If I
actually do this as such, it returns all the records. Is there
anything that can be done to achieve such a thing?
You can think of using a CASE for good short circuit mechanism
WHERE
CASE
WHEN #referenceModelId is not null AND ReferenceModelId = #referenceModeleId THEN 1
WHEN #referenceMakeId is not null AND ReferenceMakeId = #referenceMakeId THEN 1
WHEN #referenceModelId is null AND #referenceMakeId is null THEN 1
ELSE 0
END = 1

SQL: select all rows if parameter is null, else only select matching rows

I have a variable coming into a stored procedure. This variable can either have a value or be null.
If the variable is null, I need to select all the rows in the table (some with NULL values, some with actual data).
If the variable is not null, I only need to select the rows where the variable matches a column.
I created this conditional statement to help explain what I would like to achieve:
if
#status is null, select all the rows (rows with NULL for table.status, and rows with actual data for table.status)
else
select the rows where #status equals table.status
This is what I came up with (well one of them):
WHERE
book.book_nme LIKE #search_input AND
book.book_desc LIKE #search_input AND
(book.author LIKE ISNULL(#author, book.author)) AND
(bookStatus.status_desc LIKE ISNULL(#status, bookStatus.status_desc))
The only problem is that if bookStatus.status_desc is NULL, then it will not select that row (when #status is null)
I'm so confused, I tried looking up Coalesce too which seemed to prioritize the values, but ... I don't know what to do.
Should I just create a huge CASE in the stored procedure and have two select statements?
WHERE book.book_nme LIKE #search_input AND
book.book_desc LIKE #search_input AND
(#author IS NULL OR book.author LIKE #author) AND
(#status IS NULL OR bookStatus.status_desc LIKE #status) ...
Update
Added both conditions, for #author and #status
If you think it about your description it breaks down as:
Return all rows when #status is null
Otherwise return rows that match #status.
You can express the last line of your sql to match this like this:
(#status is null OR bookStatus.status_desc LIKE #status)
I always use this:
WHERE fieldname = ISNULL(#parameter, fieldname)
Hope this helps
Roger
where(field1 like isnull(#parameter,field1))
If the paramater is null will retrieve all data from field1
like
select field from table1
This works on sybase.

Alternative to NULL check and then OR for optional paramaters

I use this pattern for optional filter paramaters in my SQL Stored Procedures
AND (
#OptionalParam IS NULL OR
(
Id = #OptionalParam
)
)
However the OR is not a friend of the query optimizer. Is there a more efficient way to do this without using dynamic SQL
You can try using COALESCE. Not sure if it will be more efficient.
AND Id = Coalesce(#OptionalParam, Id)
This will not work if Id itself is null and you are using ANSI nulls.
AND ID = ISNULL(#OptionalParam, ID)
or you if you had multiple optional parameters can use
AND ID = COALESCE(#OptionalParam1, #OptionalParam2, ID)
This is definitely faster than using an OR statement.
Like the other answerer mentioned, this will not work if the ID column is null (but then again, the original statement wouldn't either).
You could try:
AND Id = CASE WHEN #OptionalParam IS NULL THEN Id ELSE NULL END
I doubt this will optimize much better, but there's no OR in it.
Alternatively, you could break your query apart into two components -- one with just an #OptionalParam IS NULL test and another with an Id = #OptionalParam test, then UNION them together. Depending on your data topology this might yield better results. It could also be significantly worse.

SQL procedure where clause to list records

I have a stored procedure that will query and return records based on if items are available or not. That part is easy, Im simply passing in a variable to check where available is yes or no.
But what I want to know is how do I throw a everything clause in there (i.e available, not available, or everything)?
The where clause right now is
where availability = #availability
The values of availabitility are either 1 or 0, nothing else.
You can use NULL to represent everything.
WHERE (#availability IS NULL OR availability = #availability)
SELECT *
FROM mytable
WHERE #availability IS NULL
UNION ALL
SELECT *
FROM mytable
WHERE availability = #availability
Passing a NULL value will select everything.
This query will use an index on availability if any.
Don't know the type of #availability, but assuming -1 = everything then you could simply do a
where #availability = -1 OR availability = #availability
multiple ways of doing it. Simpliest way is is to set the default value of the #availability to null and then your where clause would look like this
WHERE (#availability IS NULL OR availability = #availability)

Conditional Check in Where clause

i have a procedure in which the below condition is to be written in a WHERE clause. How do I do that.
itemid is a parameter which can be null.
if itemid is available then add it to my where clause,else do nothing
Some people use this technique
... WHERE #itemid IS NULL OR tbl.itemid = #itemid
It guarantees though that you will never get an index seek on the itemid column.
A better approach if the table is at all big is to split the query up into 2 separate cases
IF(#itemid IS NULL)
SELECT foo FROM bar
ELSE
SELECT foo FROM bar WHERE itemid = #itemid
If the number of combinations is too large you can consider dynamic SQL. Be sure you understand SQL injection first.
Ref: Dynamic Search Conditions in T-SQL
e.g.
SELECT Something
FROM SomeTable
WHERE (#MyParam IS NULL OR SomeField = #MyParam)
AND AnotherField = 1
You'll want to test this in your specific scenario for performance. If it's a simple query i.e. without a lot of conditional parameters, you might want to try this instead for performance:
IF ( #MyParam IS NULL )
SELECT Something
FROM SomeTable
WHERE AnotherField = 1
ELSE
SELECT Something
FROM SomeTable
WHERE SomeField = #MyParam
AND AnotherField = 1