t sql "select case" vs "if ... else" and explaination about "begin" - sql

I have few experiences with t sql and I have to write a stored.
This is my stored:
USE myDatabase
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[myStored]
(
#myPar1 INT,
#myPar2 SMALLDATETIME
)
AS
BEGIN
SET NOCOUNT ON
IF EXISTS (
SELECT
1
FROM
myTable1
WHERE
myPar1 = #myPar1
AND myPar2 = #myPar2
)
BEGIN
DELETE FROM
myTable1
WHERE
myPar1 = #myPar1
AND myPar2 = #myPar2
END
ELSE
IF EXISTS (
SELECT
1
FROM
myTable2
WHERE
myPar2 = #myPar2
)
BEGIN
INSERT INTO
myTable1
(myField1, myField2, myField3, myField4)
VALUES
(#myPar1, #myPar2, '', 1)
END
ELSE
IF EXISTS (
SELECT
1
FROM
myTable3
WHERE
myPar2 = #myPar2
)
BEGIN
INSERT INTO
myTable1
(myField1, myField2, myField3, myField4)
VALUES
(#myPar1, #myPar2, '', 1)
END
END
And these are my questions:
1 - Are there macroscopic errors?
2 - Someone suggest to use "SELECT CASE" someone else to use "IF ... ELSE", what's the difference? And what is the best option for my stored?
3 - I'm not sure about the use of the "BEGIN ... END" statement, in particular in combination with "IF ... ELSE" statement. What does it mean? Is it necessary to put "BEGIN ... END" inside the "IF ... ELSE" statement? Also for executing a single instruction?

For a single IF Statement
IF (Some Condition) --<-- If condition is true control will get inside the
BEGIN -- BEGIN ..END Block and execute the Code inisde
/* Your Code Here*/
END
All the single IF statements will check the Conditions Independently.
ONE IF with ONE ELSE
IF (Some Condition) --<-- If condition is true control will get inside the
BEGIN -- BEGIN ..END Block and execute the Code inisde
/* Your Code Here*/ -- IF not true control will jump to Else block
END
ELSE --<-- You dont mention any condition here
BEGIN
/* Your Code Here*/
END
Only One block of code will execute IF true then 1st block Otherwsie ELSE block of code.
Multiple IFs and ELSE
IF (Some Condition) --<--1) If condition is true control will get inside the
BEGIN -- BEGIN ..END Block and execute the Code inisde
/* Your Code Here*/ -- IF not true control will check next ELSE IF Blocl
END
ELSE IF (Some Condition) --<--2) This Condition will be checked
BEGIN
/* Your Code Here*/
END
ELSE IF (Some Condition) --<--3) This Condition will be checked
BEGIN
/* Your Code Here*/
END
ELSE --<-- No condition is given here Executes if non of
BEGIN --the previous IFs were true just like a Default value
/* Your Code Here*/
END
Only the very 1st block of code will be executed WHERE IF Condition is true rest will be ignored.
BEGIN ..END Block
After any IF, ELSE IF or ELSE if you are Executing more then one Statement you MUST wrap them in a BEGIN..END block. not necessary if you are executing only one statement BUT it is a good practice to always use BEGIN END block makes easier to read your code.
Your Procedure
I have taken out ELSE statements to make every IF Statement check the given Conditions Independently now you have some Idea how to deal with IF and ELSEs so give it a go yourself as I dont know exactly what logic you are trying to apply here.
CREATE PROCEDURE [dbo].[myStored]
(
#myPar1 INT,
#myPar2 SMALLDATETIME
)
AS
BEGIN
SET NOCOUNT ON
IF EXISTS (SELECT 1 FROM myTable1 WHERE myPar1 = #myPar1
AND myPar2 = #myPar2)
BEGIN
DELETE FROM myTable1
WHERE myPar1 = #myPar1 AND myPar2 = #myPar2
END
IF EXISTS (SELECT 1 FROM myTable2 WHERE myPar2 = #myPar2)
BEGIN
INSERT INTO myTable1(myField1, myField2, myField3, myField4)
VALUES(#myPar1, #myPar2, '', 1)
END
IF EXISTS (SELECT 1 FROM myTable3 WHERE myPar2 = #myPar2)
BEGIN
INSERT INTO myTable1(myField1, myField2, myField3, myField4)
VALUES(#myPar1, #myPar2, '', 1)
END
END

I don't see any macroscopic error
IF ELSE statement are the one to use in your case as your insert or delete data depending on the result of your IF clause. The SELECT CASE expression is useful to get a result expression depending on data in your SELECT statement but not to apply an algorithm depending on data result.
See the BEGIN END statement like the curly brackets in code { code }. It is not mandatory to put the BEGIN END statement in T-SQL. In my opinion it's better to use it because it clearly shows where your algorithm starts and ends. Moreover, if someone has to work on your code in the future it'll be more understandable with BEGIN END and it'll be easier for him to see the logic behind your code.

There are no errors in this script.
Case statement is for expression evaluation and not for statement execution. Hence, cannot be used in this current requirement. For more details about case statement look at http://msdn.microsoft.com/en-us/library/ms181765.aspx
Usually, a statement can be single or a compound. Compound ones are a combination of statements. For an IF condition, one can specify a single or compound statement and SQL server chose to group it inside a BEGIN .. END (unlike few other databases/programming languages). This is same for ELSE. Hence, IF should be followed by BEGIN...END and ELSE should be followed by BEGIN...END. For more details please refer to http://msdn.microsoft.com/en-us/library/ms182717(v=sql.120).aspx

Related

Passing dynamic Variable IN WHERE statement IN SQL

I have a WHERE statement where a DateOfService must be bookended between date ranges that could change. Because of this, I build an IF statement to trap the conditions and build the BETWEEN part of the statement.
Here is a Sample:
IF ISNULL(#TargetStartDate, 'N') = 'N'
BEGIN
SET #SubWhere = ' ad.EnrolledDate AND s.DateOfService'
END ELSE BEGIN
SET #SubWhere = ' #targetStartDate AND #TargetEndDate'
END
When I incorporate into WHERE clause there is no visible error. The error appears on the execution of the ALTER PROC
Here is the snippet from the WHERE clause:
AND s.DateOfService BETWEEN CAST(#SubWhere AS VARCHAR(150))
Any insight as to how to get this to work error free are much appreciated!

In a stored procedure how to skip to next query statement even if the previous statement fails

I'm hoping someone can give me an idea on how to handle this situation. I have a stored procedure that updates various tables. Some queries require connecting to different linked servers. Sometimes those linked servers are down and i need the procedure to still run the next statements regardless. Below is an example:
--Stored Procedure
BEGIN
INSERT INTO table1
SELECT *
FROM Z1;
-- IF ABOVE FAILS GO TO NEXT QUERY ANYWAY
INSERT INTO table1
SELECT *
FROM Z2;
-- IF ABOVE FAILS GO TO NEXT QUERY ANYWAY
INSERT INTO table1
SELECT *
FROM Z3;
END
You can probably do what you want with TRY/CATCH blocks:
BEGIN
BEGIN TRY
INSERT INTO table1 SELECT * FROM Z1;
END TRY
BEGIN CATCH
-- you can do something here if you want
END CATCH;
-- IF ABOVE FAILS GO TO NEXT QUERY ANYWAY
BEGIN TRY
INSERT INTO table1 SELECT * FROM Z2;
END TRY
BEGIN CATCH
-- you can do something here if you want
END CATCH;
-- IF ABOVE FAILS GO TO NEXT QUERY ANYWAY
BEGIN TRY
INSERT INTO table1 SELECT * FROM Z3;
END TRY
BEGIN CATCH
-- you can do something here if you want
END CATCH;
END;
This handles runtime errors. If you have compile time errors -- such as tables not existing or the columns not matching between the tables, then this doesn't help.
If this were run from say ssms as a bunch of ordinary queries, I would've put batch separators between each of them to treat them separately. However since this is a stored procedure you can't do that. One way to get around that could be to make one stored procedure of each query and put all of them as steps inside a SQL Server Agent job. You run the job and each step runs in order from top to bottom even if some in the middle fail.
even this will also work: ##ROWCOUNT is oracle's equivalent of sql%rowcount
--Stored Procedure
BEGIN
INSERT INTO table1
SELECT *
FROM Z1;
IF ##ROWCOUNT <>1
INSERT INTO table1
SELECT *
FROM Z2;
IF ##ROWCOUNT <>1
INSERT INTO table1
SELECT *
FROM Z3;
END

Execute insert statement when the case conditions are satisfied

I have a stored procedure which has a insert statement.The procedure executes an insert statement when the user provides all the values as 0. If the user provides differnt values then a error statement should be returned.
case when #test1=0,#test2=0,#test3=0 then
{Insert statement}
Else
Case when #test1=0,#test2=0,#test3=1
{select “All cases should be 0”}
Else
Select “Please provide data”
In this case I thought case conditions works fine but after reading documentation and some other links it seems syntactically false to write such a statement.
Anyother possible way to solve the problem.
For control flow in T-SQL, use if, not case. Something like this:
if #test1=0 and #test2=0 and #test3=0
begin
{Insert statement}
end;
Else if #test1=0 and #test2=0 and #test3=1
begin
{select “All cases should be 0”}
end
Else
begin
Select “Please provide date”
end;
You can use IF and to check each variable with 0 value then COALESCE and NULLIF are helpful as below:
IF (#test1 = 0 AND #test2 = 0 AND #test3 = 0)
BEGIN
INSERT INTO tmpTable(val1)
SELECT val1 FROM <table_name>
END
ELSE IF COALESCE(NULLIF(#test1, 0), NULLIF(#test2, 0), NULLIF(#test3, 0)) IS NOT NULL
BEGIN
SELECT 'All cases should be 0'
END
ELSE
BEGIN
SELECT 'Please provide data'
END

instead of trigger result output

I have created my first trigger. Please see the code section for the trigger below.
The triggers and the results are as expected, except for one thing.
So when I run the code below it will not insert the values into my table so the number of records remains unchanged.
insert into MatlabSearchPath(directory, userName)
values('madeup', 'default')
In the messages window though I get two lines. I don't understand why I see two lines and in particular 1 row affected - the number of records in my table hasn't changed?
(0 row(s) affected)
(1 row(s) affected)
Trigger
create trigger trDefaultPathInsert on DVLP_QES.dbo.MatlabSearchPath
instead of insert
as
begin
declare #defCount int
declare #retVal int
select #defCount = count(userName) from inserted where userName = 'Default'
if (#defCount > 0)
begin
select #retVal = count(HostName) from DVLP_QES.dbo.UserHostName where HostName = HOST_NAME()
if (#retVal > 0)
begin
insert into MatlabSearchPath select * from inserted
end
else
begin
insert into MatlabSearchPath select * from inserted where inserted.userName <> 'Default'
end
end
end
Update
I should mention that there a 3 triggers on this table, one is the trigger above the other one is a delete & the last one is an update
Your trigger does the following:
Counts records you are trying to insert, where userName equals 'Default'
In your case, count is 1.
Pay attention to your collation - if it's case sensitive, you are going to skip that whole branch of code.
If you enter the if branch, next thing trigger checks is if there are rows in UserHostName table where HostName equals host name of your client; pay attention that you don't think it should be host name of your server or something like that
If you enter the TRUE-branch, it should insert everything to the table; however, if not, it shouldn't insert anything. Of course, except if the collation is case sensitive, then revert the logic.
I I were you, I would add PRINT statements into trigger, just to make sure how does it execute.
create trigger trDefaultPathInsert on DVLP_QES.dbo.MatlabSearchPath
instead of insert
as
begin
declare #defCount int
declare #retVal int
select #defCount = count(userName) from inserted where userName = 'Default'
PRINT '#defCount'
PRINT #defCount
if (#defCount > 0)
begin
select #retVal = count(HostName) from DVLP_QES.dbo.UserHostName where HostName = HOST_NAME()
PRINT '#retVal'
PRINT #retVal
if (#retVal > 0)
begin
PRINT 'TRUE-BRANCH'
insert into MatlabSearchPath select * from inserted
end
else
begin
PRINT 'FALSE-BRANCH'
insert into MatlabSearchPath select * from inserted where inserted.userName <> 'Default'
end
end
EDIT
It seems that the message about rows affected can't be controlled inside the trigger. Even the standard SET NOCOUNT ON on the trigger beginning won't stop it from showing. This gave me notion that the message is a result of the trigger being successfully finished by calling it with X rows, where X will eventually be in the X row(s) affected message.
This SO question furtherly confirms the problem.
The situation here if the first message indicating cero is because the instead of trigger is uses to ignore the insert you sent and do instead whats in the trigger
You can debug your code with management studio

How Can I Check If Any IF Block Executed In SQL Server

In my SQL Server stored procedure, I have a number of IF blocks.
IF #CurrentStatus IN (1, 4) AND #RoleID IN ('ADMN', 'PMGR', 'SMGR', 'DMGR', 'DESI', 'DERO')
BEGIN
-- SELECT query...
END
IF #CurrentStatus = 2 AND #RoleID IN('ADMN')
BEGIN
-- SELECT query...
END
There are several more IF blocks like these. When none of the queries are executed because the conditions of the IF are not met, there will be no data returned. I have a query I want to return as the default if there is no other data being returned. How can I check if any data is being returned at the end of my stored procedure?
I tried checking if any queries had been executed with IF ##ROWCOUNT = 0 but when one of the IF blocks executed, I would get 2 result sets.
If I understand correctly, you could use If / Else If / Else, like this...
IF #CurrentStatus IN (1, 4) AND #RoleID IN ('ADMN', 'PMGR', 'SMGR', 'DMGR', 'DESI', 'DERO')
BEGIN
-- SELECT query...
END
Else IF #CurrentStatus = 2 AND #RoleID IN('ADMN')
BEGIN
-- SELECT query...
END
Else
BEGIN
-- Default query
END