Tuesday, January 6, 2009

/** Use WHILE and BREAK statements alongwith IF blocks to form flow similar to Switch Statements in Procedures and Functions **/

/* With successful use of while block and break statements,
I came up with an thought of acheving a flow similar to Switch Case statements, from programming langauge, in SQL.
Yes there is a case statement that we can use for Selecting, updating etc. But we cannot use the same for builing a business logic.
That is we cannot use a Switch or Case block that channels the flow of a business logic in Procedures, functions or mere scripts.
Hush!!! its hard to explain for me, but please try to imagine that I want to Select 'A' and then update table t1 if a @i is 1.
And Select 'B' and then delete table t3 if @i is 5. This, as far as I am aware, we cannot acheive with a single case Block in SQL.
Thus the following code.
*/



Declare @caseFlag Varchar(20)

SET @caseFlag = 'A'

WHILE 1 = 1
BEGIN

.....IF @caseFlag = 'A'
.....BEGIN
..........Print ' GOT A '
........../* Some other logic */
..........BREAK;
..... END

.....IF @caseFlag = 'B'
.....BEGIN
..........Print ' GOT B'
........../* Some other logic */
..........BREAK;
..... END

.....PRINT 'Got else'

.....BREAK ; -- REMOVING OR COMMENTING THIS BREAK WILL CAUSE AN INFINITE . .....WHILE LOOP.
END
/* I have use a true condition just to enter the block.
I check for conditions with the help of if statements.
Then break fom the block after the objective is acheived.
Pls note that if the last Break Statement is removed or commented, it would result in an infinite while loop.
One more advantage of this code would be that we can use any expression that evaluate to TRUE OR FALSE as Cases.
*/
---


/*
After testing the code above I just thought,
it would be great if could use it just like a switch statements that we use in Programming langauges.
Then I realised that I would need the flow to fall down from one case to another if I dont use a Break statement.
To acheive this, I have commented out the BREAK statements in the IF blocks and added the exepression to the blocks below it.
This would allow the flow to fall through the cases just as in Switch statements in programming languages.

*/
Declare @caseFlag Varchar(20)

SET @caseFlag = 'A'

WHILE 1 = 1
BEGIN

.....IF @caseFlag = 'A'
.....BEGIN
..........Print ' GOT A '
........../* Some other logic */
..........-- BREAK;
.....END

.....IF @caseFlag = 'B' OR @caseFlag = 'A'
.....BEGIN
..........Print ' GOT B'
.......... /* Some other logic */
..........-- BREAK;
.....END

.....PRINT 'Got else'

.....BREAK ; -- REMOVING OR COMMENTING THIS BREAK WILL CAUSE AN INFINITE . .....WHILE LOOP.
END

/* This just a basic idea and can be twisted and turned to acheive more custom flows.
May be something like Falling through case 'A' but not going to 'B' and then still go through a case 'C'
that could be introduced. I can think of many more such examples but I sure you got the basic idea and can play more with it.
Please do let me know if this blog helped you or in what way I could improve it.
Please do suggest any improvement or any other method you can think of to acheive this.
All suggestions are warmly welcome.
*/

/* Using While FOR conditional flow instead of IF */

/* This is not something I would do usually.
I dont break rules unless absolutely justified. (Though, I do love to do so.)
So was the reason here.

I had to execute the below complicated logic in somewhat better and easy manner.
The task I had to acheive was to import data into a table and append it if @append is 1.
Else truncate the table and populate the fresh data. But I had to keep history before doing so.
So I must populate the history table only if @append is 0 and @keepHistory is 1 and then truncate the original table.
If @append and @keepHistory were both 0 I must not keep a history but still truncate the table.
This can be acheived with If block as shown below.
( Pls note I have not used actual tables to protect client Information. But I still would like to present the flow)
*/


DECLARE @append BIT
DECLARE @successful BIT
DECLARE @keepHistory BIT
DECLARE @err INT

IF @append = 0
BEGIN
........................Set @successful = 1;
........................IF @keepHistory = 1
........................BEGIN
...............................Insert into TblHistory
..............................SELECT * FROM tablename

..............................SET @err = @@error;

..............................IF ( @err <> 0 )
..............................BEGIN
............................................................ --ON ERROR do not truncate table.
................................... SET @successful = 0;
.............................. END
........................END
/* if successful truncate the table */
........................IF @successful = 1;
........................ BEGIN
.............................. truncate table tablename;
........................ END
END

/* The above code looks cumbersome and complicated to me.
And this might invite some bugs if someone tries to change the code after several days.
To avoid this I needed some structure similar to a Case statement or BREAK in Programming Langauges like JAVA, C++ etc.
I devised similar logic with WHILE block and BREAK statements in SQL.
Please suggest if there is a better or even if there is any other way to acheive this that you can think of.
I would be more than delighted to know it.

*/


---

DECLARE @append BIT
DECLARE @successful BIT
DECLARE @keepHistory BIT
DECLARE @err INT

WHILE @append = 0
BEGIN
........IF @keepHistory = 1
........BEGIN
................ Insert into TblHistory
................ SELECT * FROM tablename

................ SET @err = @@error;

................ IF ( @err <> 0 )
................ BEGIN
........................ SET @successful = 0;
........................BREAK; -- terminate without truncating the table.
................ END
........ END

........ TRUNCATE TABLE tablname;
........BREAK; -- REMOVING OR COMMENTING THIS BREAK WILL CAUSE AN INFINITE WHILE LOOP.
END

/* With the use of while block and break statements I had to use less number of variables for acheiving the flow.
I have still used @successful even though it was unneccessary because I need it in the rest of the flow after the while block.
In this logic the table would not be truncated if there was an error while transfering data to history.
It is somewhat similar to returning from a function/procedure in SQl
or other programming langauges without executing some part of code on error.
Yes and I try to avoid all the GOTO statements for all the obvious reasons.
Also please note that commenting or removing the last break statement will result in an infinite while loop.
I hope this was helpful to you.
All suggestions are warmly welcome.
*/