Does parameter position matter in where clause of SQL Query - sql

Declare #temp As Int
set #temp = 10
select Column1 from MyTable where Column2 = #temp
select Column1 from MyTable where #temp = Column2
Is there any change in performance based on position of parameter in where clause.

There should be no change. However, You can confirm this by running the execution plan in sql viewer.

No, those two should be identical.

Related

Only select rows if at least one exists

I have the following query:
IF EXISTS ( SELECT Column1 ,
Column2
FROM dbo.Table1
EXCEPT
SELECT Column1 ,
Column2
FROM #proposedData )
BEGIN
SELECT Column1 ,
Column2
FROM dbo.Table1
EXCEPT
SELECT Column1 ,
Column2
FROM #proposedData
RAISERROR('Unexpected values in proposed data',16,10)
END
I want to raise an error if the data that already exists in a table does not appear in a table variable. This is to make sure that my source code matches what is in a particular environment. The problem with this is that the two select queries are duplicate code. This introduces a possibility for human error - the two queries should be the same but could be different. An alternative is:
SELECT Column1 ,
Column2
FROM dbo.Table1
EXCEPT
SELECT Column1 ,
Column2
FROM #proposedData
IF ##ROWCOUNT <> 0
BEGIN
RAISERROR ('Invalid ObjectType values',16,10)
END
However this 'pollutes' the query output as there will be an empty result set if the data is correct. So, is there way to prevent a result set being output if there are 0 rows? An idea is a stored proc that takes the select and constructs the first example query from it but was wondering there was a built in way to do it.
Thanks
Joe
How about this ?
if exists(SELECT Column1 ,
Column2
FROM dbo.Table1
EXCEPT
SELECT Column1 ,
Column2
FROM #proposedData)
RAISERROR ('Invalid ObjectType values',16,10)

Conditional filter in WHERE clause

How can I set a conditional filter in a SQL WHERE clause? For example, I have a parameter #ID with the following procedure
SELECT * FROM myTable WHERE Column1 = 'test' AND Column2 = #ID
However, If #ID = -1 I don't want the last part of the SQL (AND Column2 = #ID) included
I realize I can make an if statement with 2 separate queries, however this is a large script and has this same issue multiple times, so I was hoping there was a better way than nearly duplicating several queries
This is ok for T-SQL:
SELECT * FROM myTable WHERE Column1 = 'test' AND (#ID = -1 OR Column2 = #ID)
Just include the condition in your SQL as an OR, note the brackets
SELECT * FROM myTable WHERE Column1 = 'test' AND (#ID = -1 OR Column2 = #ID)
One alternative:
SELECT * FROM myTable WHERE Column1 = 'test' AND #ID in (-1,Column2)

Behaviour of SELECT #Var and SET #Var in T-SQL when dealing with NULLs

Everyday I learn something new, it seems :) Can someone please explain to me the rationale behind the following code behavior:
DECLARE #A INT
SET #A = 15
SET #A = (SELECT ValueThatDoesntExist FROM dbo.MyTable WHERE MyColumn = 'notfound')
SELECT #A
-- Rsultset is NULL
SET #A = 15
SELECT #A = ValueThatDoesntExist FROM dbo.MyTable WHERE MyColumn = 'notfound'
SELECT #A
-- Resultset is 15
From what I see, SET changes the value of the variable if the resultset is NULL, while SELECT doesn't. Is this normal ANSI behavior or is it T-SQL specific?
Of, course, if I do SELECT #A = NULL, the assignment happens correctly.
The first version sets A to the result of a query:
SET #A = (SELECT ValueThatDoesntExist FROM dbo.MyTable WHERE MyColumn = 'notfound')
Basically the select in in scalar context, and if it doesn't find a row, it evaluates to null.
The second version sets A for each row in the result set:
SELECT #A = ValueThatDoesntExist FROM dbo.MyTable WHERE MyColumn = 'notfound'
Since there are no rows, A is never assigned to. Another example:
declare #a int
select #a = i
from (
select 1
union all select 2
union all select 3
) as SubQueryAlias(i)
order by
i
select #a
This will assign 3 values to #a. The last one assigned is 3, so that's what the query prints.
Well the select returns no rows. So practically there is not assignment.
While the set will have a null as a result.
Variable assignment in a SELECT clause is rather unpredictable. When you have:
SELECT #A = ...
and exactly one row is in the result set, the value is well defined. If multiple rows are returned, the value may be computed once, for an arbitrary row, or it may be computed multiple times, up to the number of rows in the result set.
However, if the query produces zero rows, then the assignment is never performed.
SET #A = (SELECT ValueThatDoesntExist
FROM dbo.MyTable WHERE MyColumn = 'notfound')
Here NULL is returned as a result of executing the query
But when you do
SELECT #A = ValueThatDoesntExist FROM dbo.MyTable WHERE MyColumn = 'notfound'
there is nothing returned from the query

Usage of COALESCE for no rows returned

I have used COALESCE numerous times but I suppose I never encountered this particular situation. Assume there is only one row per #param1.
select #test = COALESCE (column1, 'default') FROM Table1 WHERE column3 = #param1
In this scenario, if the value of column1 is null, 'default' is selected when the sql statement actually returns a row. What if there are no matching records for #param1.
Lets say I want to always have a default value for #test. Is the following correct or is there another way?
select #test = COALESCE( (select column1 FROM Table1 WHERE column3 = #param1), 'default').
I presumed that, select #test = COALESCE (column1, 'default') FROM Table1 WHERE column3 = #param1, will contain 'default' even if it did not return a row. Nope.
I suppose I can also check if #test is NULL afterwards and assign a default value as well.
You already effectively mentioned the answer... Use COALESCE after/outside the SELECT, as otherwise you never actually assign a value (which is different from assigning a NULL value)...
SELECT #test = NULL
SELECT #test = column1 FROM Table1 WHERE column3 = #param1
SELECT #test = COALESCE(#test, 'default')
Or simply...
SELECT #test = COALESCE((SELECT column1 FROM Table1 WHERE column3 = #param1), 'default')
You could also just give the variable the default value at declaration. If no rows are returned by the query no assignment will be made.
DECLARE #test VARCHAR(10) = 'default'
SELECT #test = COALESCE(column1, #test) /*Might not need COALESCE
if column1 is not nullable*/
FROM Table1
WHERE column3 = #param1
SELECT #test

SQL: Cancel 'where' on null parameter

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)