SQL: Cancel 'where' on null parameter - sql

This may be obvious but I'm getting very confused.
I have an SQL query with a where clause (where in with a list of parameters). If all of these parameters are null, I need the SQL to ignore the where clause and retrieve all the records. Is this easy to do in SQL? I know one way around it is to just remove the where clause using code if the parameters are null.

You could try do something like this:
select *
from foo
where (#parameter1 is null AND #parameter2 is null)
OR (#parameter1 = 'value1'
AND
#parameter2 = 'value2')
Offcourse it needs a bit of tuning in your own query, but now you will check if the parameters are null or do your original where-clause.

The most performant way is to not include the WHERE clause at all if that's an option for you.
You often see tricks such as WHERE X=#X OR #X IS NULL used but these can lead to sub optimal plans and unnecessary table scans in the event you are passing a specific value for #X
Edit:
As this answer seems to have met with some unexpected scepticism...
create table #t
(
id varchar(5) primary key /*varchar to test LIKE without causing any casts*/
)
INSERT INTO #t
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM sys.all_columns
SET STATISTICS IO ON
/*Test the equals */
EXEC sp_executesql N'
SELECT *
FROM #t
WHERE (#id IS NULL OR id = #id)', N'#id varchar(5)', #id='1'
/*Is `LIKE` any better? */
EXEC sp_executesql N'
SELECT *
FROM #t
WHERE (#id IS NULL OR id LIKE #id)', N'#id varchar(5)', #id='1'
/*What should the plan look like? */
EXEC sp_executesql N'
SELECT *
FROM #t
WHERE (id = #id)', N'#id varchar(5)', #id='1'
DROP TABLE #t

if it's a stored procedure, either you do with dynamic SQL and do not append the where clause at all if parameters are null, or you still use an IF ELSE and write the query twice in the IF and in the else one with the where and one without, I agree with Martin that the where should be fully avoided if all records should be retrieved.

...
WHERE
(
col1 IS NULL
AND col2 IS NULL
AND col3 IS NULL
) OR
(
conditions...
);

i really think this will work
Where ((CASE WHEN #Parameter1 is null then 1 else 0 end) = 1 and
(CASE WHEN #Parameter2 is null then 1 else 0 end) = 1)

Have a look here handling-optional-parameters for an article fitting your requirements. The article compares various ways of doing optional parameters and discusses different versions of SQL Server as well as the performance of each.
I think what you are after is an individual IS NULL + OR per column, right?
WHERE (#col1 IS NULL OR col1 LIKE #col1)
AND (#col2 IS NULL OR col2 = #col2)

Related

SQL Server EXEC a raw SQL query inside of the SELECT statement

I have a table, which contains an external table name where I can find a value that I need (that table doesn't have any PKs/FKs, I can not change this).
The thing is, is it possible to execure a dynamic SQL query inside of the SELECT statement ?
Something like
SELECT Col1,
Col2,
'SELECT TOP 1 Col from ' + Col3,
FROM Table1
I'm not sure if this is exactly what you are looking to do, but this might be a solution if the value you would like to concatenate is going to be the same (which it looks like from the TOP 1 in the example):
IF OBJECT_ID('atest') IS NOT NULL
DROP TABLE atest
CREATE TABLE [dbo].[atest](
[id] [int] NULL,
[value] [varchar](50) NULL,
[X] [varchar](50) NULL
) ON [PRIMARY]
INSERT INTO atest (id, value, X)
VALUES (1, 'ONE', 'EXTRA STUFF'),
(2, 'TWO', 'OTHER'),
(3, 'THREE', 'NOT THIS')
DECLARE #X VARCHAR(100) = (SELECT TOP 1 X FROM atest)
SELECT [id], [value] + '-->' + #X FROM atest
This would result in:
1 ONE-->EXTRA STUFF
2 TWO-->EXTRA STUFF
3 THREE-->EXTRA STUFF
You could also make a temp table, or do self joins. I think there are some solutions here to get you what you want. Good luck! :)
Not directly, but you could consider selecting the values form Table1 into temp table and then using dynamic UPDATE statement to add the value form table specified by col3. Not elegant and have not tried on DB, but something like this might get you around problem
SELECT Col1,
Col2,
Col3
TopOfCol3Table = ''
INTO #TempTable1
FROM Table1
DECLARE #Sql VARCHAR(1024) = '
UPDATE #TempTable1
SET TopOfCol3Table = (SELECT TOP 1 Col FROM ' + Col3 ')'
EXECUTE sp_executesql #Sql
You can execute TSQL commands by calling the stored procedure sp_executesql that takes your TSQL command text as parameter.
Here's some documentation about it: sp_executesql (Transact-SQL)
What you do with the result is all part of your implementation.

Using SQL Server CASE statement in WHERE

I want to select records from a table in a stored procedure. Given parameters can be empty or a string including some keys separated by comma (1, 2, etc)
I want to manage that when a parameter is an empty string, "WHERE" ignore searching.
I'm using this code:
where (CASE when #PatientID <> 0 then ( dental.ID_Sick in (1,2)) else (1=1) end)
Something like that is working in W3School. I mean:
SELECT * FROM Customers
WHERE (case when 1=1 then (Country IN ('Germany', 'France', 'UK')) else 1=1 end);
What is the problem in my query that does not work? SQLServerManagementStudio is giving error on "IN" statement.
Solution:
The best way to handle such optional parameters is to use dynamic SQL and built the query on the fly. Something like....
CREATE PROCEDURE myProc
#Param1 VARCHAR(100) = NULL
,#Param2 VARCHAR(100) = NULL
,#Param3 VARCHAR(100) = NULL
,#ListParam VARCHAR(100) = NULL
--, etc etc...
AS
BEGIN
SET NOCOUNT ON;
Declare #Sql NVARCHAR(MAX);
SET #Sql = N' SELECT *
FROM TableName
WHERE 1 = 1 '
-- add in where clause only if a value was passed to parameter
+ CASE WHEN #Param1 IS NOT NULL THEN
N' AND SomeColumn = #Param1 ' ELSE N'' END
-- add in where clause a different variable
-- only if a value was passed to different parameter
+ CASE WHEN #Param2 IS NOT NULL THEN
N' AND SomeOtherColumn = #Param3 ' ELSE N'' END
-- List Parameter used with IN clause if a value is passed
+ CASE WHEN #ListParam IS NOT NULL THEN
N' AND SomeOtherColumn IN (
SELECT Split.a.value(''.'', ''VARCHAR(100)'') IDs
FROM (
SELECT Cast (''<X>''
+ Replace(#ListParam, '','', ''</X><X>'')
+ ''</X>'' AS XML) AS Data
) AS t CROSS APPLY Data.nodes (''/X'') AS Split(a) '
ELSE N'' END
Exec sp_executesql #sql
, N' #Param1 VARCHAR(100), #Param2 VARCHAR(100) ,#Param3 VARCHAR(100) ,#ListParam VARCHAR(100)'
, #Param1
, #Param2
,#Param3
, #ListParam
END
Problem with Other approach
There is a major issue with this other approach, you write your where clause something like...
WHERE ( ColumnName = #Parameter OR #Parameter IS NULL)
The Two major issues with this approach
1) you cannot force SQL Server to check evaluate an expression first like if #Parameter IS NULL, Sql Server might decide to evaluate first the expression ColumnName = #Parameterso you will have where clause being evaluated even if the variable value is null.
2) SQL Server does not do Short-Circuiting (Like C#), even if it decides to check the #Parameter IS NULL expression first and even if it evaluates to true, SQL Server still may go ahead and evaluating other expression in OR clause.
Therefore stick to Dynamic Sql for queries like this. and happy days.
SQL Server does not have a Bool datatype, so you can't assign or return the result of a comparison as a Bool as you would in other languages. A comparison can only be used with IF-statements or WHERE-clauses, or in the WHEN-part of a CASE...WHEN but not anywhere else.
Your specific example would become this:
SELECT * FROM Customers
WHERE 1=1 OR Country IN ('Germany', 'France', 'UK')
It would be better readable to rewrite your statement as follows:
WHERE #PatientID = 0
OR dental.ID_Sick in (1,2)
Referring to your actual question, I'd advise to read the linked question as provided by B House.
May be this straight way will work for you
IF (#PatientID <> 0)
BEGIN
SELECT * FROM Customers
WHERE Country IN ('Germany', 'France', 'UK')
END
try this:
WHERE 1=(CASE WHEN #PatientID <>0 AND dental.ID_Sick in (1,2) THEN 1
WHEN #PatientID =0 THEN 1
ELSE 0
END)

EXEC sproc COALESCE (value1,value2)

I need to EXEC a stored procedure which requires a COALESCE if a field value is null use another field value.
EXEC dbo.TestSproc COALESCE ('Field1','Field2')
Would anyone be able to advise on how best to code this?
This will be called in a SQL Job so needs to be one line.
Alternatively:
declare #field1 bigint = (select Field1 from table1);
declare #field2 bigint = (select Field2 from table2);
declare #isnull bigint = isnull(#field1, #field2);
exec dbo.TestSproc #isnull
CASE statement for when that field us NULL
CASE WHEN field IS NULL
THEN COALESCE ('Field1','Field2')
ELSE 0 END

Executing a WHERE clause conditionally in SQL

I have an application on a SQL Server 2008 database. This database has a stored procedure that queries one of the tables. This stored procedure takes two parameters: userName and ID
The userName parameter will always be passed. However, the ID field will either be NULL or an actual value. If the value is something other than NULL, I need to consider it in the WHERE clause of my query. Unfortunately, I'm not positive how to do this. Currently, I'm trying
SELECT
*
FROM
TaskTicket t
WHERE
t.[UserName]=#userName AND
-- This is where I am stumped
Thank you for your help!
SELECT
*
FROM
TaskTicket t
WHERE
t.[UserName]=#userName
AND (#ID IS NULL OR t.[ID] = #ID)
Try this:
SELECT
*
FROM
TaskTicket t
WHERE
t.[UserName]=#userName AND
(#ID is null
or -- replace this comment with your logic
)
Group the conditionals together
select *
from TaskTicket t
Where t.[UserName]=#userName AND
((t.Id is null and (conditions_when_id_is_null))
or
(t.Id is not null and (conditions_when_id_is_not_null)))
SELECT
<column list>
FROM
TaskTicket T
WHERE
T.[UserName] = #username AND
(T.id = #id OR #id IS NULL)
Just be aware that this may cause a non-optimal query plan in some cases. That's probably not a big deal in this case unless your table is huge and you don't have an index on UserName and ID.
Hopefully more efficient than using an OR condition:
SELECT
*
FROM
TaskTicket t
WHERE
t.[UserName]=#userName AND
t.[ID] LIKE COALESCE(#ID,'%')
NB: will only work if ID is a non-NULLable, character field. (You can use CAST and COALESCE on t.[ID] otherwise, but then it's unlikely to be more efficient than an OR condition.)
Alternatively, use dynamic SQL in your stored procedure to completely omit the t.[ID] condition, if #ID is NULL.
declare #SQL nvarchar(max)
declare #WHERE_ID nvarchar(20)
set #WHERE_ID =
(
CASE
WHEN #ID is null THEN ''
ELSE ' AND ID = ' + CAST(#ID as nvarchar(10))
END
)
set #SQL = 'SELECT * FROM TaskTicket WHERE UserName = ' + #userName + #WHERE_ID
EXEC #SQL
Create procedure Procedure1
(
#Param1 nvarchar(100)=null,
)
AS
BEGIN
SELECT
ColumnName1,ColumneName2
FROM TableName
WHERE
(#Param1 IS NULL OR ColumnName1=#Param1)
END

how to validate the input parameters before using in the static query?? SQL server 2005

consider table1 with 2 columns..
table1:
column1 int,
column2 char
create procedure SP1(#col1,#col2) as
begin
select * from table1 where _______
end
Question: User may enter valid input for either (col1 or col2) or (both col1 and col2).so i need to validate the user input and use those correct column(s) in the satic query.
eg: if both inputs are correct then, the query will be:
select * from table1 where column1=#col1 and column2 =#col2
if only col2 is valid and col1 is not a valida one, then this:
select * from table1 where column2=#col2
how to validate the input parameters before using in the static query?? in sql server 2005
You mean something like:
Create Procedure Sp1( #Col1..., #Col2... )
As
-- if #Col1 is not valid, then set it to Null
If #Col1 <> <valid number or string or date>
Set #Col1 = Null
-- if #Col2 is not valid, then set it to Null
If #Col2 <> <valid number or string or date>
Set #Col2 = Null
Select ...
From Table1
Where ( #Col1 Is Not Null Or #Col2 Is Not Null )
And ( Col1 = #Col1 Or #Col1 Is Null )
And ( Col2 = #Col2 Or #Col2 Is Null )
try this:
Create Procedure Sp1( #Col1..., #Col2... )
As
If #Col1 {is valid} AND #Col2 {is valid}
BEGIN
select * from dbo.table1 where column1=#col1 and column2 =#col2
END
ELSE #Col2 {is valid}
BEGIN
select * from dbo.table1 where column2=#col2
END
RETURN 0
GO
be careful using the (#col1 IS NULL or #Col1=Col1) trick, an index will not be used. Read Dynamic Search Conditions in T-SQL by Erland Sommarskog to see all the PROs and CONs of each dynamic search method. I chose the If method because the OP only lists 2 conditions to search on, so it would seem feasible to do it this way.
In such case it looks like dynamic SQL will be the best option - you will generate the WHERE clause depending on the validity of arguments and then execute the whole query with sp_executesql