SQL IF EXISTS with OR Condition - sql

I am facing a performance issue with a SQL statement. I have noticed a performance degradation in one SQL statement in one of a procedure.
SQL Statement:
IF EXISTS(SELECT TOP 1 FROM TABLE1 WHERE COLUMN1 = 'XYZ') OR #ISALLOWED = 1
BEGIN
-- SQL Statements
END
I couldn't able to understand why OR statement with IF Exists statement is causing performance issue in above query. Because if I rewrite the above statement like this:
DECLARE #ISVALUEEXISTS BIT
SET #ISVALUEEXISTS = 0
IF EXISTS(SELECT TOP 1 FROM TABLE1 WHERE COLUMN1 = 'XYZ')
SET #ISVALUEEXISTS = 1
IF (#ISVALUEEXISTS = 1 OR #ISALLOWED = 1 )
BEGIN
--SQL Statements
END
Then performance issue is gone. So, I'm couldn't able to understand how and why OR condition with IF Exists statement is causing problem.
Anyone has any idea about this?

If you have this query inside stored procedure this could happen because of parameter sniffing.
Try something like this to check it:
declare #ISALLOWED_internal
select #ISALLOWED_internal = #ISALLOWED
IF EXISTS(SELECT TOP 1 FROM TABLE1 WHERE COLUMN1 = 'XYZ') OR #ISALLOWED_internal = 1
BEGIN
-- SQL Statements
END

Related

How to Update a column Before Select?

I am setting a stored procedure for select and I want to update the value of one column in the database Before doing the Select.
This is what I tried but it's not working.
#roleID int and #query varchar(240)
SELECT
EP.Equipe_Projet_Id AS PROJET_ID,
U.USR_ID,
CleRepartition = CASE
WHEN #RoleID = 1 AND #query IS NOT NULL
THEN 100
AND (UPDATE EQUIPE_PROJET SET CleRepartition = 100
WHERE EP.Equipe_Projet_Id = #PROJET_ID AND EP.Role_Id = 3)
ELSE NULL
END
FROM
[EQUIPE_PROJET] EP
Expecting update of column on database and having it's value
i want to update the value of Column CleRepartition in the database while selecting.
This is not possible in a SELECT query. A SELECT retrieves data from the database. An UPDATE modifies data. These are two separate statements and cannot be combined.
You are doing this work in a stored procedure. Within a stored procedure, you can run an UPDATE and SELECT in any order, so you can accomplish both tasks. If you are concerned about data changing in the database between the two statements, you can wrap them in a transaction.
Stored procedure can do update then select after.
So I added the query of update in the beginning, then I do the select.
Like this:
UPDATE EP
SET CleRepartition = CASE
WHEN #RoleID = 1 AND #query IS NOT NULL
THEN 100
AND (UPDATE EQUIPE_PROJET
SET CleRepartition = 100
WHERE EP.Equipe_Projet_Id = #PROJET_ID
AND EP.Role_Id = 3)
ELSE NULL
END
FROM [EQUIPE_PROJET] EP
SELECT
EP.Equipe_Projet_Id AS PROJET_ID,
U.USR_ID,
CleRepartition
FROM
[EQUIPE_PROJET] EP
I hope that this will help someone.

SQL Query Where clause slows down query

I use to write query like this:
SELECT *
FROM myTable
WHERE COl1 = #Param1 OR #Param1 Is NUll
The above use to execute find and a decent speed. But now it takes 17 secs.
If I remove the
OR #Param1 Is NULL
It executes less than 1 sec.
SELECT *
FROM myTable
WHERE COl1 = #Param1
Executes less that 1 sec
Any idea why the OR #Param1 Is Null would add 16 sec to the execution?
I've been using this style of query for many years and haven't noticed any performance hit.
The query basically is saying give my ALL records if #param1 is null otherwise give me only the records that matach #param1
Since you are passing in #Param1 you could take a procedure based approach as outlined in the link in my original comment. This would look like the following:
CREATE PROC getData
#Param1 varchar(255) = NULL
AS
BEGIN
IF(#Param1 IS NULL)
BEGIN
SELECT *
FROM myTable
END
ELSE
BEGIN
SELECT *
FROM myTable
WHERE COL1 = #Param1
END;
END;
Try the below and let us know if this helps
SELECT *
FROM myTable
WHERE COl1 = nvl(#Param1,col1) ;
By using nvl, the value in it is not parsed first and gets the execution plan which might help performance.

SQL Set Max Affected Rows for Session

I work with a group of people in a DEV environment and sometimes we get a little anxious on the F5. I would say on a monthly basis someone updates every record in a table instead of just 1 or 2 because they miss the were clause or were doing something like
Begin Transaction
update table1
set column1 = '50'
select * from table1
where column2= 'abc'
and column3 = '123'
If ##ROWCOUNT != 1
Begin
Rollback
Print 'Failed ' + #Ticket
End
else
Begin
commit
Print 'Success ' + #Ticket
End
In this case they meant to comment or delete the select line. My question is, can you set something to auto rollback if more than X number of rows are affected? I can never see them updating more than 400 or so. I have told them to you Begin Transaction and ##RowCount to verify but since it is 2 statements and the 2nd has the right number it doesn't help.
I doubt SQL Server out of the box provides a solution for you. if this is a big issue, then deploy SQL Server database backup, with regularly scheduled log backups, so you can restore to a given point in time. Or, restrict their access so they are updating/inserting/deleting/querying from procs only (this probably won't scale, but it's an option). Or tell them to use TOP in all their queries.
In the meantime, ensure your devs never, ever, troubleshoot on a prod system.
It sounds like the developers performing these update queries need to be more rigorous. Every update-- even in development-- should be written with a begin tran and rollback until they are sure that the query updates the correct rows.
For example, I always use the following template:
-- review the data to be updated
select * from MyTable where MyColumn = 'A'
begin tran
update MyTable
set MyColumn = 'B'
where MyColumn = 'A'
-- be sure the query updated the expected number of rows
select ##rowcount
-- re-review the original data to make sure those rows were changed
select * from MyTable where MyColumn = 'A'
-- reverse the changes; change this to a commit *only* when the above is proven to be correct
rollback
-- EDIT --
Adapting this to your example, you could capture the ##ROWCOUNT in a variable and refer to it later. For example:
declare #RowsUpdated int = 0
Begin Transaction
update table1
set column1 = '50'
-- capture the ##ROWCOUNT for use later
select #RowsUpdated = ##ROWCOUNT
-- you could add row counts from multiple update statements together:
-- select #RowsUpdated = #RowsUpdated + ##ROWCOUNT
select * from table1
where column2= 'abc'
and column3 = '123'
If #RowsUpdated != 1
Begin
Rollback
Print 'Failed ' + #Ticket
End
else
Begin
commit
Print 'Success ' + #Ticket
End

Sql short circuit OR or conditional exists in where clause

I'm trying to force sql server to make a short circuit OR comparison on some fields. On the left side of the Or I have a simple variable comparison and on the right side I have a pretty 'heavy' subquery.
WHERE
(#Var = 'DefaultValue' ) OR
Exists(select * from atable)
Is there any way to only execute the right side of the or statement if the first statement is false.
I've tried case and if else statements but can't find any working syntax.
I'm using a MS SQL server
You can't do what you want in a single SQL statement. You can do something like this however in a stored proc
If #Var = 'DefaultValue' then
BEGIN
SELECT * FROM table
END
ELSE
BEGIN
SELECT * FROM table
WHERE Exists(select * from atable)
END
If you've got a lot of inputs you should consider Dynamic SQL
How about this?
WHERE 1 = CASE #Var
WHEN 'DefaultValue' THEN 1
ELSE (SELECT TOP 1 1 FROM atable)
END

T-SQL - need to run update if only one record returned by query

I need to update a record IFF there is only one record matching my search criteria. Here's what I have, but it's crude:
DECLARE #TestCount INT;
SELECT #TestCount = COUNT(*)
FROM TestRecords tr
WHERE
tr.UnitSerial = #UnitSerial
AND
tr.PassFailStatus = 1;
IF (#TestCount = 1)
UPDATE
TestRecords
SET
Invalid = 1
WHERE
TestRecordID =
(SELECT TestRecordID
FROM TestRecords tr
WHERE
tr.UnitSerial = #UnitSerial
AND
tr.PassFailStatus = 1);
Of course this is example code - there are more restrictions and tables joins, etc in the SELECT statement, and it's all wrapped by a transaction, but this is the gist of the stored proc logic.
I'm thinking there has to be a better way but I don't know what that is. Any suggestions?
Thanks, Dave
You could do it in one query as:
with toupdate as (
select tr.*,
count(*) over () as cnt
from TestRecords tr
where tr.UnitSerial = #UnitSerial AND tr.PassFailStatus = 1
)
update toupdate
set Invalid = 1
where cnt = 1
This assumes you are using SQL 2005 or greater.
I think your code will run without problems!
Use ##ROWCOUNT variable to determine how many records was affected by a SELECTE, UPDATE, INSERT statement: but in your case you have just set your #TestCount variable with the same result!
It's not far off what I would do, which is simply:
IF (SELECT COUNT(*) FROM x WHERE y = z) = 1
BEGIN
--statements
END
Of course, you could replace the condition with anything, e.g. a UDF with more complex dynamic conditions.