BREAK description in BOL - sql-server-2005

SQL Server 2005 BOL says about BREAK:
Exits the innermost loop in a WHILE or IF…ELSE statement.
I don't understand this part about IF…ELSE. It looks like you can put BREAK inside IF. Actually BREAK works only inside WHILE, and control flow pass after loop's END. BREAK not in a WHILE context fires error, and that's completely OK.
My question is - why documentation mention IF...ELSE?
BTW, SQL Server 2000 BOL says only this:
Exits the innermost WHILE loop.

SQL 2008 BOL says:
Exits the innermost loop in a WHILE
statement or an IF…ELSE statement
inside a WHILE loop.
which is probably what the SQL 2005 documentation should have said.

The SQL2008 explanation still seems somewhat confusing however. To me it implies that break in an IF…ELSE statement inside a WHILE loop would just exit the IF…ELSE. This is not the case.
DECLARE #i INT = 0
WHILE #i<10
BEGIN
IF(#i=3)
BEGIN
PRINT 'i=3'
BREAK
END
ELSE
BEGIN
PRINT 'i<>3'
END
SET #i = #i+1
END
PRINT 'out of while'
Prints
i<>3
i<>3
i<>3
i=3
out of while

Related

Use of variable with Boolean data Type in EvalExpression in For Loop container in SSIS

I have a data flow task set in a For Loop Container. The loop should be executed for as long as the variable #LastPayment is not positive.
#LastPayment is a variable of DataType: Boolean, Value=False, EvaluateAsExpression=False and with the following set in Expression
"SELECT [Continue] FROM [DW_Test].[dbo].[Test]"
In my For Loop Editor, I have my EvalExpression set as :
#[LastPayment]="1"
When I run the SSIS package, the Loop does not stop even though SELECT [Continue] FROM [DW_Test].[dbo].[Test] gives return of 0 after a few iteration, hence #[LastPayment]="1" is FALSE after a few iteration. I do not understand why the ForLoop is not ending.
When I changed the EvalExpression to In my For Loop Editor to
#[LastPayment]=(DT_BOOL)"TRUE" or #[LastPayment]="TRUE", I get the same results.
When I changed the EvalExpression to In my For Loop Editor to #[LastPayment]="0"
No rows are generated.
Is there something wrong in my variable definition or the EvalExpression? Appreciate any advice on this. Thanks.
SSIS Booleans are not evaluated the same as SQL Server Bits. The way to test if a Boolean variable is true is like this:
#[LastPayment] == true
Just to update that I have resolved this.
Before the ForLoop process, I added a Execute SQL Task to determine the MaxLoop that the ForLoop process needs to go through and mapped the result set to variable #MaxLoop of datatype Int32.
In the ForLoop container, I added an expression task with expression #Loop=#Loop + 1. #Loop is a variable of datatype Int32. This is to count the number of loops the ForLoop has been processed.
My ForLoop EvalExpression is amended to #Loop<#MaxLoop.
Thanks for all the suggestions.
If you want to check logical expression in a For Loop, you should write it as #LastPayment<=0. Microsoft explains conditional expressions.

While loop with multiple conditions in T-SQL

Let me start out by saying I know I KNOW that these kind of loops are horrible and you shouldn't use them in Transact SQL. But, for some purposes (those purposes being irrelevant so don't ask me "what're you trying to do!?") ya just have to. I don't want to, but I gotta.
Anyway. Is there some way to have a while loop in T-SQL terminate on a complex conditional statement? like, in C# I'd just say while (i > -10 && i < 10) , because I want the loop to terminate when the sentinel value is between -10 and 10, but I just... can't figure out how to do it.
It's probably excruciatingly simple... or.. impossible. Please advise.
Right now, I've just got
WHILE #N <> 0
BEGIN
--code and such here
END
You must look at declaration of WHILE statement:
WHILE Boolean_expression
{ sql_statement | statement_block | BREAK | CONTINUE }
First of all you can use complex Boolean_expression as Dan said:
WHILE #N > -1 AND #N <10
BEGIN
END
If you want to add more flexibility to you code you can use IF with BREAK, something like this:
WHILE #N > -1 AND #N <10
BEGIN
-- code
IF (SELECT MAX(ListPrice) FROM Production.Product) > $500
BREAK
END
-- code
END
to go out of cycle or use CONTINUE to skip one cycle.
I feel like a complete idiot. And I'm sure I look like one too.
I tried all that stuff, trying to get the condition to work. I just could not figure out why it wasn't working.
It just hit me. I was changing the code while I was debugging it, and it wasn't executing my changes.
I'm pretty embarrassed. I was doing it right after all. I was just... doing it wrong.

Block-scope for local variable

Is there a better way to create an arbitrary block in VB.Net to limit the scope of a local variable? If have tried "If 1 Then", but it just looks kludgy.
If 1 Then
Dim table = InputParameter1
Dim new_row = table.AddRow
new_row.field(1) = InputParameter3.user_value
End If
I just don't want to have table and new_row accessible later in the procedure.
Re-factor your procedure so there's another procedure in which table and new_row do their thing. If you really don't need them to be visible later on, then they are doing a distinct sub-task that should be refactored anyway.
Generally speaking, when you can partition your code into N segments, where each segment has no dependency on the others, then you are looking at N tasks and preferably N procedures.
This goes back to the rule that any procedure should do one thing, and multiple segments are a sign that it's doing more than one thing.
With Option Strict On, that'd have to be If True Then, but the more preferred option (as far as I have seen) is Do ... Loop While False.
But, no there is no syntax like a simple Begin ... End (or { ...}).
If you can work with an IDisposable, and have it disposed at the end of the block, Using newVariable = AnIDisposable gives you the closest to what you're describing, but like I said, it is disposed at the end.

Why did this the SQL parser execute this illegal syntax?

I have a stored procedure in this form:
ALTER PROCEDURE [dbo].[fooBar]
(
)
AS
BEGIN
-- etc
RETURN #Success
END
It had been working perfectly with BEGIN and END in it before, but after changing something and reverting it back, it refused to execute, pointing to a syntax error at the last END (removing that next pointed to a syntax error at the first IF/BEGIN/.... statement inside the procedure, and thus begins your wild goose chase).
Looking at the MSDN official documentation for the syntax, BEGIN and END used in this way to envelope a stored procedure is illegal. (Removing the BEGIN and END solved the problem)
Question: Why did this happen?
Did the compiler skip over this BEGIN and END initially and later discover it? Are there some things that the SQL compiler ignores? Is it legacy? Is it just finicky? Am I missing a hotfix?
This is SQL Server 10.50.1617
BEGIN/END are perfectly valid for a stored procedure. This is explicitly set in the grammar at the documentation page you linked to.
It is the parentheses that are not allowed.

Common Table Expression Error

I have to use old school ADODB (not ADO.NET) to execute a statement that contains a Common Table Expression.
I am using (have to use) the SQLOLEDB provider.
The DML statement works fine when executing from a Windows 7 / Windows Server 2008 client but not from WinXP or Win2K3 server.
I have profiled the routine and found that the old OSes send a slightly different SQL statement.
Win7 + 2008 = exec sp_executesql N'WITH source(Vsl, Cpt, SrcTyp, SrcNum, Opn, JobNum, Qty, Cst, Vry, Reg, Vnt, Sbk) AS ...'
WinXP + Win2K3 = exec sp_executesql N'exec WITH source(Vsl, Cpt, SrcTyp, SrcNum, Opn, JobNum, Qty, Cst, Vry, Reg, Vnt, Sbk) AS ...'
Notice the extra 'exec' slipped into the command text.
It appears as if the verions of SQLOLEDB.1 on the old OSs mis-treats the WITH statement and sees it as needing a prepending 'exec'.
Can anyone shed some light on this. Is there an SQLOLEDB driver update that I can apply to the old OSes? or some other workaround.
(FYI, You should really revisit some of your existing questions, as most of them seem to have helpful answers that appear to address the question; your comments even suggest this is so. If they have an answer, please accept it).
If you really need to use a CTE here (meaning you're doing something recursive and aren't just using it for convenience instead of inline-selecting or inline-joining), the simplest and fastest workaround would probably be to include your SQL within your own call to sp_executesql. You'll end up nesting calls to it (which will look silly), but it shouldn't cause any actual problems.
Wrapping the query up in an sp_executesql statement works great if you don't have parameters in the query, otherwise the parameters aren't parsed because they're in a quoted string by the time they get to ADO, and this results in a syntax error.
What I did to resolve this was to create a TADOQuery descendant, which overrides the constructor, as follows:
constructor TCPADOQuery.Create(AOwner: TComponent);
begin
inherited;
TWideStringList(SQL).OnChange := LocalQueryChanged;
end;
LocalQueryChanged then checks if the query starts with a common table expression, and inserts a dummy declaration at the beginning of the query, which the XP ADO parser does understand. A CTE must be preceded by a semicolon if it is not the first statement in the query, so we have to fix that first:
procedure TCPADOQuery.LocalQueryChanged(Sender: TObject);
var
a: WideString;
begin
if not (csLoading in ComponentState) then
Close;
a := Trim(SQL.Text);
if Uppercase(copy(a, 1, 4)) = 'WITH' then a := ';' + a;
if Uppercase(copy(a, 1, 5)) = ';WITH' then
a := 'DECLARE #DummyForADO_XP BIT'#13#10 + a;
CommandText := a;
end;
This has resolved the problem, and has saved me having to rework all of my code where I use both CTEs and parameters.