What is the alternate of Goto in Azure Synapse - azure-synapse

I am using goto in azure synapse to skip certain code and jump to the label, its not working as expected. what is the alternate for that.

As GOTO is not supported in Azure Synapse Analytics, dedicated SQL pools, you need to write procedure code that does not rely on GOTO.
This example is taken from the help page for GOTO and works perfectly fine on normal SQL Server:
DECLARE #Counter int;
SET #Counter = 1;
WHILE #Counter < 10
BEGIN
SELECT #Counter
SET #Counter = #Counter + 1
IF #Counter = 4 GOTO Branch_One --Jumps to the first branch.
IF #Counter = 5 GOTO Branch_Two --This will never execute.
END
Branch_One:
SELECT 'Jumping To Branch One.'
GOTO Branch_Three; --This will prevent Branch_Two from executing.
Branch_Two:
SELECT 'Jumping To Branch Two.'
Branch_Three:
SELECT 'Jumping To Branch Three.';
This is that same code refactored without GOTO, using IF ELSE control flow language and BEGIN END blocks to contain multiple statements and BREAK to exit the loop:
DECLARE #Counter INT;
SET #Counter = 1;
WHILE #Counter < 10
BEGIN
SELECT #Counter
SET #Counter = #Counter + 1
IF #Counter = 4
BEGIN
SELECT 'Jumping To Branch One.'
SELECT 'Jumping To Branch Three.';
BREAK
END
IF #Counter = 5
BEGIN
SELECT 'Jumping To Branch Two.'
END
END
There would be multiple ways to do it, eg write some of the inner code as functions or stored procedures. This is just a simple example. I have to say, I have not written a GOTO statement in SQL code for years as it tends to lead to so-called spaghetti code and can be hard to debug.

Related

Can't execute a while clause in SQL Server with Dbeaver

I am trying to execute a loop while in Dbeaver with SQL Server, but the statement keeps loading and does not execute it. I just want to print the word 'ok!' 3 times.
I'm not sure if it's a loop problem, a Dbeaver problem, or another.
Can anyone help please?
My code:
DECLARE #cnt INT = 0;
WHILE #cnt < 3
BEGIN
PRINT 'ok!';
END;
Screenshot from Dbeaver
#cnt never increments, so this loop will never finish. It will never yield control back to the system to let it even show the first ok string. You need to add this:
DECLARE #cnt INT = 0;
WHILE #cnt < 3
BEGIN
PRINT 'ok!';
Set #cnt = #cnt + 1;
END;
Anyway, 99 times out of a 100, if you're writing a loop in SQL at all you're doing something very wrong. SQL really wants to operating on whole sets at a time, not individual items in the sets via loops.

WAITFOR DELAY doesn't act separately within each WHILE loop

I've been teaching myself to use WHILE loops and decided to try making a fun Russian Roulette simulation. That is, a query that will randomly SELECT (or PRINT) up to 6 statements (one for each of the chambers in a revolver), the last of which reads "you die!" and any prior to this reading "you survive."
I did this by first creating a table #Nums which contains the numbers 1-6 in random order. I then have a WHILE loop as follows, with a BREAK if the chamber containing the "bullet" (1) is selected (I know there are simpler ways of selecting a random number, but this is adapted from something else I was playing with before and I had no interest in changing it):
SET NOCOUNT ON
CREATE TABLE #Nums ([Num] INT)
DECLARE #Count INT = 1
DECLARE #Limit INT = 6
DECLARE #Number INT
WHILE #Count <= #Limit
BEGIN
SET #Number = ROUND(RAND(CONVERT(varbinary,NEWID()))*#Limit,0,1)+1
IF NOT EXISTS (SELECT [Num] FROM #Nums WHERE [Num] = #Number)
BEGIN
INSERT INTO #Nums VALUES(#Number)
SET #Count += 1
END
END
DECLARE #Chamber INT
WHILE 1=1
BEGIN
SET #Chamber = (SELECT TOP 1 [Num] FROM #Nums)
IF #Chamber = 1
BEGIN
SELECT 'you die!' [Unlucky...]
BREAK
END
SELECT
'you survive.' [Phew...]
DELETE FROM #Nums WHERE [Num] = #Chamber
END
DROP TABLE #Nums
This works fine, but the results all appear instantaneously, and I want to add a delay between each one to add a bit of tension.
I tried using WAITFOR DELAY as follows:
WHILE 1=1
BEGIN
WAITFOR DELAY '00:00:03'
SET #Chamber = (SELECT TOP 1 [Num] FROM #Nums)
IF #Chamber = 1
BEGIN
SELECT 'you die!' [Unlucky...]
BREAK
END
SELECT
'you survive.' [Phew...]
DELETE FROM #Nums WHERE [Num] = #Chamber
END
I would expect the WAITFOR DELAY to initially cause a 3 second delay, then for the first SELECT statement to be executed and for the text to appear in the results grid, and then, assuming the live chamber was not selected, for there to be another 3 second delay and so on, until the live chamber is selected.
However, before anything appears in my results grid, there is a delay of 3 seconds per number of SELECT statements that are executed, after which all results appear at the same time.
I tried using PRINT instead of SELECT but encounter the same issue.
Clearly there's something I'm missing here - can anyone shed some light on this?
It's called buffering. The server doesn't want to return an only partially full response because most of the time, there's all of the networking overheads to account for. Lots of very small packets is more expensive than a few larger packets1.
If you use RAISERROR (don't worry about the name here where we're using 10) you can specify NOWAIT to say "send this immediately". There's no equivalent with PRINT or returning result sets:
SET NOCOUNT ON
CREATE TABLE #Nums ([Num] INT)
DECLARE #Count INT = 1
DECLARE #Limit INT = 6
DECLARE #Number INT
WHILE #Count <= #Limit
BEGIN
SET #Number = ROUND(RAND(CONVERT(varbinary,NEWID()))*#Limit,0,1)+1
IF NOT EXISTS (SELECT [Num] FROM #Nums WHERE [Num] = #Number)
BEGIN
INSERT INTO #Nums VALUES(#Number)
SET #Count += 1
END
END
DECLARE #Chamber INT
WHILE 1=1
BEGIN
WAITFOR DELAY '00:00:03'
SET #Chamber = (SELECT TOP 1 [Num] FROM #Nums)
IF #Chamber = 1
BEGIN
RAISERROR('you die!, Unlucky',10,1) WITH NOWAIT
BREAK
END
RAISERROR('you survive., Phew...',10,1) WITH NOWAIT
DELETE FROM #Nums WHERE [Num] = #Chamber
END
DROP TABLE #Nums
As Larnu already aluded to in comments, this isn't a good use of T-SQL.
SQL is a set-oriented language. We try not to write procedural code (do this, then do that, then run this block of code multiple times). We try to give the server as much as possible in a single query and let it work out how to process it. Whilst T-SQL does have language support for loops, we try to avoid them if possible.
1I'm using packets very loosely here. Note that it applies the same optimizations no matter what networking (or no-networking-local-memory) option is actually being used to carry the connection between client and server.

Speed up simple update statement in postgres for 1 million rows

I have a very simple sql update statement in postgres.
UPDATE p2sa.observation SET file_path = replace(file_path, 'path/sps', 'newpath/p2s')
The observation table has 1513128 rows. The query so far has been running for around 18 hours with no end in sight.
The file_path column is not indexed so I guess it is doing a top to bottom scan but it seems a bit excessive the time. Probably replace is also a slow operation.
Is there some alternative or better approach for doing this one off kind of update which affects all rows. It is essentially updating an old file path to a new location. It only needs to be updated once or maybe again in the future.
Thanks.
In SQL you could do a while loop to update in batches.
Try this to see how it performs.
Declare #counter int
Declare #RowsEffected int
Declare #RowsCnt int
Declare #CodeId int
Declare #Err int
DECLARE #MaxNumber int = (select COUNT(*) from p2sa.observation)
SELECT #COUNTER = 1
SELECT #RowsEffected = 0
WHILE ( #RowsEffected < #MaxNumber)
BEGIN
SET ROWCOUNT 10000
UPDATE p2sa.observation
SET file_path = replace(file_path, 'path/sps', 'newpath/p2s')
where file_path != 'newpath/p2s'
SELECT #RowsCnt = ##ROWCOUNT ,#Err = ##error
IF #Err <> 0
BEGIN
Print 'Problem Updating the records'
BREAK
END
ELSE
SELECT #RowsEffected = #RowsEffected + #RowsCnt
PRINT 'The total number of rows effected :'+convert(varchar,#RowsEffected)
/*delaying the Loop for 10 secs , so that Update is completed*/
WAITFOR DELAY '00:00:10'
END
SET ROWCOUNT 0

Programmatic T-SQL in ad-hoc sql scripts

Is it possible to use T-SQL programming constructs outside the confines of stored procedures and functions? Specifically, can they be used in ad-hoc sql scripts? If so, is the full range of capabilities available (aside from passing in parameters and returning values that I guess would only be supported in stored procedures and functions)?
I'm from an Oracle PL/SQL background. PL/SQL can be used in stored procedures and functions, but also within anonymous PL/SQL code blocks that can be used in ad-hoc sql scripts and do not get stored in the DB. I'd like to know if T-SQL has similar capabilities.
Yes they can take this example solution to the fizzbuzz problem:
declare #counter int
declare #output varchar(15)
set #counter = 1
while #counter < 101
begin
set #output = ''
if #counter % 3 = 0
set #output = 'Fizz'
if #counter % 5 = 0
set #output = #output + 'Buzz'
if #output =''
set #output = #counter
print #output
set #counter = #counter + 1
end
Of course don't fall into the trap of using procedural code to work with data, SQL works best treating data as a set.

Sybase SQL stored procedure consumes too much memory

I am trying to run a stored procedure with a while loop in it using Aqua Data Studio 6.5 and as soon as the SP starts Aqua Data starts consuming an increasing amount of my CPU's memory which makes absolutely no sense to me because everything should be off on the Sybase server I am working with. I have commented out and tested every piece of the SP and narrowed the issue down to the while loop. Can anyone explain to me what is going on?
create procedure sp_check_stuff as
begin
declare
#counter numeric (9),
#max_id numeric (9),
#exists numeric (1),
#rows numeric (1)
select #max_id = max(id)
from my_table
set #counter = 0
set #exists = 0
set #rows = 0
while #count <= #max_id
begin
//More logic which doesn't affect memory usage based
//on commenting it out and running the SP
set #counter = #counter + 1
set #exists = 0
set #rows = 0
end
end
return
How many times does the while loop iterate? I suspect Aqua Data Studio is building up data structures as the query runs and for every iteration of the loop, a further block of memory is needed to catalogue the plan/stats of that iteration.