BEGIN..END not working in Nested IF..ELSE - sybase

I am confused with the BEGIN.. END in the nested IF..ELSE condition.
For example, when I am trying to execute below mentioned query. It is
returning an error -- "Incorrect syntax near ElSE.."
IF ( ISNULL(#tin,'')=''AND ISNULL(#prpr_ntwrk,'')<>'' )
BEGIN
IF (ISNULL(#prpr_ntwrk,'')='P')
BEGIN
-- CODE
END
ELSE
BEGIN
-- CODE
END
END
please suggest.

The code below executes on ASE 15.7.0
DECLARE #tin varchar, #prpr_ntwrk varchar
IF ( ISNULL(#tin,'')=''AND ISNULL(#prpr_ntwrk,'')<>'' )
BEGIN
IF (ISNULL(#prpr_ntwrk,'')='P')
BEGIN
SELECT "P"
END
ELSE
BEGIN
SELECT "Not P"
END
END
Note that ASE gets confused with the empty stubs "-- Code" in the original example.
Your first IF statement may not do what you want, but I am sticking to the question asked.

Here are my recommendations :
1.-Give more whitespaces in this part of your code so it can be legible and avoid problems.
IF ( ISNULL(#tin,'')=''AND ISNULL(#prpr_ntwrk,'')<>'' )
2.- Insert a new line after the last END
3.- Run everything on terminal with isql because interactive SQL can be buggy sometimes
4.-Post the code between the if and end please.
Hope it helps

Related

Why does query execution continue after RETURN?

Consider following script:
IF OBJECT_ID('tempdb.dbo.#INTERMED', 'U') IS NOT NULL
DROP TABLE #INTERMED;
IF OBJECT_ID('tempdb.dbo.#INTERMED1', 'U') IS NOT NULL
DROP TABLE #INTERMED1;
PRINT 'Inserting INTO #INTERMED'
GO
SELECT 11 AS Col1
INTO #INTERMED
RETURN -- Why does execution continue below this line?
PRINT 'Inserting INTO #INTERMED1' -- This doesn't print anything
GO
SELECT 'Testing testing 123' AS Col2
INTO #INTERMED1
SELECT * FROM #INTERMED1 i
When you run it in SSMS you will notice that RETURN is ignored, PRINT statement after RETURN doesn't do anything and then execution continues.
Can someone explain why? I would expect it to exit immediately after RETURN.
I did find that it is somehow related to GO statements because if I commented out all GO statements it behaves as expected (exits after RETURN) but I still don't have an explanation.
GO is not part of the SQL Language. It's a batch separator used by Management Studio, and adopted as a convention by some other tools as well, but it has no special meaning in the language itself. Try to use it in a stored procedure and see what I mean.
Therefore, what happens is you have one batch the looks like this:
IF OBJECT_ID('tempdb.dbo.#INTERMED', 'U') IS NOT NULL
DROP TABLE #INTERMED;
IF OBJECT_ID('tempdb.dbo.#INTERMED1', 'U') IS NOT NULL
DROP TABLE #INTERMED1;
PRINT 'Inserting INTO #INTERMED'
It does it's thing, and then you have a new batch that looks like this:
SELECT 11 AS Col1
INTO #INTERMED
RETURN -- Why does execution continue below this line?
PRINT 'Inserting INTO #INTERMED1' -- This doesn't print anything
It runs to the RETURN statement, at which point the batch, and only that batch, returns/finishes. However, there is still one more batch to run:
SELECT 'Testing testing 123' AS Col2
INTO #INTERMED1
SELECT * FROM #INTERMED1 i
Again, this is a whole new batch. The previous RETURN statement means nothing. It's like you called three methods in sequence.
I also saw this in the comments:
The reason I had GO in it is to actually have PRINT statements output something while script is still executing.
There's a better way. Look into the RAISERROR statement:
RAISERROR('My Progress Message',0,1) WITH NOWAIT

Limits on ADO connection execute queries

I have a SQL script that does quite a few updates. When I retrieve the script (in a Classic ASP page) from a text file and attempt to execute it, it does not appear to apply all the updates I expect yet if I copy and paste the content into Management Studio, the query works fine. I cannot work out why this might be the case. Is there a limit as to how many statements/operations you can include in such a script?
Also the execute command oConn.Execute strSql does not fail, it just moves to the next line of classic ASP code. Is there any way I can test for errors?
Unfortunately I don't have enough reputation to comment on your question, but have you tried wrapping your code in TRANSACTION blocks? Very useful if things go wrong.
As for error handling, you can refer to the ##ERROR...
DECLARE #ErrorVar INT
RAISERROR(N'Message', 16, 1);
IF ##ERROR <> 0
-- This PRINT statement prints 'Error = 0' because
-- ##ERROR is reset in the IF statement above.
PRINT N'Error = ' + CAST(##ERROR AS NVARCHAR(8));
GO
Paul set me on the right track here, thank you. I've been coding SQL for years but confess I have dabbled only a little in the world of transactions. After the code below I put other stats and the failure message into a table that I interrogate in the ASP code after calling the script.
BEGIN TRY
BEGIN TRANSACTION
--My long update script placed in here
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION
SET #FailMsg = ERROR_MESSAGE() + ' Failed at line ' + CAST(ERROR_LINE() as varchar) + '.'
END
END CATCH

Terminate IF block in Transact-SQL

This is probably quite a rookie question, but I can't find in the MSDN examples online of how to end an IF/ELSE block in Transact-SQL. For example, I want to create a SP that does this:
USE [MyDb];
GO
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
CREATE PROCEDURE [dbo].[usp_MyStoredProc]
#param1 DATE, #param2 INT, #param3 BIT, #param4 [dbo].[CustomDataType] READONLY
WITH EXEC AS CALLER
AS
-- Only run this part if #param3 == true
IF (#param3 = 1)
BEGIN
--do stuff...
END
-- I don't really need an else here, as I'm simply doing an
-- extra step at the beginning if my param tells me to
-- I always want this next part to run...
-- do more stuff...
GO
I have a solution that I think works (posted as answer below), but I feel like I'm working around my lack of knowledge instead of doing the best pattern.
Edit- I deleted my first solution as it was a horrible idea and didn't want others to try implementing that. Turns out the question was actually the solution in this case; thanks to all.
The syntax for the IF statement is
IF Boolean_expression
{ sql_statement | statement_block }
[ ELSE
{ sql_statement | statement_block } ]
The ELSE part is optional.
A "sql_statement" is any single statement. A "statement_block" is a group of statements wrapped in a BEGIN and END
More details:http://msdn.microsoft.com/en-us/library/ms182717.aspx
There doesn't have to be an else statement. Whatever's between the BEGIN/END will be run if it meets the IF condition and then your SQL will progress normally after that. It's the same thing as:
If (x == 1) {
// condition met, do stuff
}
// do more stuff
You were really close. Just needed some tweaking.
IF (#param3 = 1)
BEGIN
-- do stuff if a param tells me to (has to be done before main block of code is ran below)
END
-- do stuff that should always be ran.
GO
Do yourself and your team a favor: never use a goto unless it's 100% necessary. Usually, they are not necessary with well-structured code.

Short circuit in IF clause

I have searched and found nothing about it (I believe it is impossible to do it). My problem is that I have to check if a temporary table exists and also if there is some specific data on that temporary table.
Did anyone faced this before? How did you managed to solve it? I would like to avoid creating milions of IF..ELSE blocks.
EDIT:
IF (OBJECT_ID('tempdb..#tempTable') IS NOT NULL
AND EXISTS (SELECT * FROM #tempTable WHERE THIS_COLUMN = 'value'))
BEGIN
PRINT 'Temp table and data exists'
END
ELSE
BEGIN
PRINT 'Temp table or data does not exist'
END
This is what I want to do. The problem comes when the tempTable doesn't exist (that could happen). It throws an error because, although the first stamement returns false, it continues to execute the second statement. And the SELECT statement is not able to find the table and therefore throws the error. The solution I found was to do this:
IF OBJECT_ID('#tempTable') IS NOT NULL
BEGIN
IF EXISTS (SELECT * FROM #tempTable WHERE THIS_COLUMN = 'value'
BEGIN
PRINT 'Temp table and data exists'
END
ELSE
BEGIN
PRINT 'Temp table exists but data does not exist'
END
END
ELSE
BEGIN
PRINT 'Temp table does not exist'
END
My question would be, is there a way of having 2 conditions and if the first condition returns false not check the second one? Kind of using && in a programming language.
What you are trying to do is not possible as this is a compile time failure and the whole statement needs to be compiled together.
It won't evaluate the first part of the statement then compile the second part only if that is true. You need to split the test for existence and the query referencing the table into two separate statements so they are compiled separately.
See here
There is no such thing as XAND logical gate (exclusive AND). In theory XAND would mean, that both operands are true or both are false. So this means XAND is the same as Equals (=), at least for bitwise logical operations.
Please show some sample code to illustrade what you are trying to do.
Regards
I have searched this sometime ago and if I remember correctly Sql Server does indeed short circuit logical conditions but it is it who decides which one it will check first regardless of the order in which they appear in the if clause.
This is probably a sketchy solution, but I sometimes use COALESCE statements to control the sorts of if, else, then structure you are trying to get at. In this case, it is a little more dirty looking because we are looking for the inverse of a coalesce statement.
DECLARE #temp_message AS varchar(100)
SELECT #temp_message = COALESCE(CASE
WHEN OBJECT_ID('tempdb..#tempTable') IS NOT NULL THEN NULL
ELSE 'Temp table does not exist'
END,
CASE
WHEN EXISTS (SELECT * FROM #tempTable WHERE THIS_COLUMN = 'value') THEN NULL
ELSE 'Specified value does not exist in temp table'
END,
'Temp table and data exists')
PRINT #temp_message
The COALESCE runs one statement after another until one does not yield a NULL value. That means you can do cool things like run a series of small queries to check some values before running a large costly query. Let me know if that is really illegitimate! It worked on my machine :)
I see two ways to get close to this in MSSQL:
First. If you use sp_executesql (dynamic sql) your stored procedure will be compiled without errors. Also if #tempTable doesn't exists server will output error but continue batch execution:
exec sp_executesql N'SELECT count(*) FROM #tempTable WHERE THIS_COLUMN = ''value'''
if ##rowcount > 0
print 'ok'
else
print 'error'
end;
Second. Just create User defined function with nested IF and EXISTS (as you do it now) which output 0 and 1. And use dynamic sql to input table name and possible filter value(s) to this UDF. In this case you can use this UDF in IF.

Can you have just a comment in a block of your SQL if-statement?

I'd like to just put in a comment in the block of my if-statement, but I get an error when I try. I want to be more like Steve McConnell.
declare #ConstraintName varchar(255)
set #ConstraintName = 'PK_Whatever'
IF LEFT(#ConstraintName, 2) = 'PK'
BEGIN
--can't drop primary keys
END
The error I get is:
Incorrect syntax near 'END'.
If I add something after the comment, i.e. PRINT #ConstraintName, it works fine.
No, you cannot have an empty if block (or one that contains only comments).
You don't say why you would want this. If you are just trying to comment out the contents of the if for debugging, you should comment the entire if.
SELECT NULL will generate a result-set and could affect client apps. Seems better to do something that will have no effect, like:
IF LEFT(#ConstraintName, 2) = 'PK'
BEGIN
DECLARE #Dummy bit -- Do nothing here, but this is required to compile
END
I can't say for sure in SQL Server, but in Oracle PL/SQL you would put a NULL statement in a block that you want to do nothing:
BEGIN
-- This is a comment
NULL;
END
Good tips here: How to do nothing in SQL Server
BEGIN
DONOTHING:
END
So you're just defining a label.
No, I don't think you can. If you want to temporarily comment that out, you'll probably need to just put a /* ... */ around the entire statement.
It's not the comment. It's that you have an empty if block. You have to have at least one statement in there. Putting in a print statement might be your best bet.
Since you can't have an "empty" blocks (thanks Charles Graham), I'll place a comment above the if-statement for the intention of the conditional (thanks BlackWasp), and then have a comment within the begin..end block that describes a dummy declare (thanks GiLM).
Do you think this is how I should comment the code?
declare #ConstraintName varchar(255)
set #ConstraintName = 'PK_Whatever'
--can't drop primary keys
IF LEFT(#ConstraintName, 2) = 'PK'
BEGIN
--do nothing here
DECLARE #Dummy bit --required to compile
END
Would it not be better to design your SQL statement around items you do wish to drop constraints for? So If you wish to remove the ability for this then
If left(#constraintname,2 <> 'PK'
BEGIN
-- Drop your constraint here
ALTER TABLE dbo.mytable DROP constraint ... -- etc
END
i know it doesn't answer your original question as to whether you can place just a comment inside a block, but why not inverse your conditional so the block only executes if <> 'PK'?
-- drop only if not primary
IF LEFT (#ConstraintName, 2) <> 'PK'
BEGIN
--do something here
END

Resources