Sybase looping not working - interactive sql - sql

im trying the do a simple cursor that will give me data , executing the cursor in a 5 seconds interval .
but it only shows 1 row and stop... im working on sybase interactive sql , this is the query:
DECLARE #codigo INTEGER
DECLARE alarm_history_cur CURSOR FOR
SELECT AlarmHistoryID FROM DBA.AlarmHistory
WHERE DBA.AlarmHistory.Area = '1'
AND DBA.AlarmHistory.DateTimeOccurred < '2021-01-01 00:00:00.000'
OPEN alarm_history_cur
FETCH NEXT alarm_history_cur INTO #codigo
while ##sqlstatus = 0
BEGIN
WAITFOR DELAY '00:00:05'
SELECT * FROM DBA.AlarmHistory WHERE AlarmHistoryID = #codigo
END
BEGIN
FETCH NEXT alarm_history_cur
INTO #codigo
END
CLOSE alarm_history_cur
DEALLOCATE CURSOR alarm_history_cur
thanks in advance for further help.
Update :
im using sybase central - sql anywhere ..i will let some pictures to you
-##version pictureenter image description here
-original select
-what actually the syntax shows
enter image description here
enter image description here

The fetch command needs to be in the same begin/end pair associated with the while loop.
Instead of this:
while ##sqlstatus = 0
BEGIN
WAITFOR DELAY '00:00:05'
SELECT * FROM DBA.AlarmHistory WHERE AlarmHistoryID = #codigo
END
BEGIN
FETCH NEXT alarm_history_cur INTO #codigo
END
Try this:
while ##sqlstatus = 0
BEGIN
WAITFOR DELAY '00:00:05'
SELECT * FROM DBA.AlarmHistory WHERE AlarmHistoryID = #codigo
FETCH NEXT alarm_history_cur INTO #codigo
END

Related

SQL count number of time series events, with some some start or stop entries missing

I have some start/stop events and I need to count the number of total events but sometimes a start or stop is missing, for example:
Time Event
10:50 START
10:52 STOP
10:59 START
11:01 STOP
11:45 STOP
Count(Event) Where Event='START'
Would return 2, I also need to count the missing START value, so the result should be 3. Any ideas on how this could be done? Thanks!
Two constraints must be met to enable event counting.
Two START-STOP periods cannot overlap.
Two consecutive and chronologically ordered START and STOP event cannot be possibly originated from two different events, namely START+(missing TOP) and (missing START)+STOP.
It the conditions are met, a simple state machine can be implemented to detect the "missing" events. Such a row-by-row logic could (almost always) be implemented using the cursor syntax.
N.B. To exemplify the generality of the cursor method you can also see other answers A (update columns), B (a tedious algo) I made. The code structures are highly similar.
Test Dataset
use [testdb];
if OBJECT_ID('testdb..test') is not null
drop table testdb..test;
create table test (
[time] varchar(50),
[event] varchar(50),
);
insert into test ([time], [event])
values ('10:50', 'START'),('10:52', 'STOP'),('10:59', 'START'),
('11:01', 'STOP'),('11:45', 'STOP'),('11:50', 'STOP'),('11:55', 'START');
select * from test;
Code
/* cursor variables */
-- storage for each row
declare #time varchar(50),
#event varchar(50),
#state int = 0, -- state variable
#count int = 0; -- event count
-- open a cursor ordered by [time]
declare cur CURSOR local
for select [time], [event]
from test
order by [time]
open cur;
/* main loop */
while 1=1 BEGIN
/* fetch next row and check termination condition */
fetch next from cur
into #time, #event;
-- termination condition
if ##FETCH_STATUS <> 0 begin
-- check unfinished START before exit
if #state = 1
set #count += 1;
-- exit loop
break;
end
/* program body */
-- case 1. state = 0 (clear state)
if #state = 0 begin
-- 1-1. normal case -> go to state 1
if #event = 'START'
set #state = 1;
-- 1-2. a STOP without START -> keep state 0 and count++
else if #event = 'STOP'
set #count += 1;
-- guard
else
print '[Error] Bad event name: ' + #event
end
-- case 2. start = 1 (start is found)
else if #state = 1 begin
-- 2-1. normal case -> go to state 0 and count++
if #event = 'STOP' begin
set #count += 1;
set #state = 0;
end
-- 2-2. a START without STOP -> keep state 1 and count++
else if #event = 'START'
set #count += 1;
-- guard
else
print '[Error] Bad event name: ' + #event
end
END
-- cleanup
close cur;
deallocate cur;
Result
print #count; -- correct answer: 5
Tested on SQL Server 2017 (linux docker image, latest version).
Well, you could count each start and then each "stop" where the preceding event is not a start:
select count(*)
from (select t.*,
lag(event) over (order by time) as prev_event
from t
) t
where event = 'start' or
(prev_event = 'stop' and event = 'stop');

SQL if then statement

retry:
exec xxxxxxxxx
if #csvfilecount < 16
begin
waitfor delay '00:05:00'
goto retry
end
else
begin
send email
end
I like to use go to retry for 2 try only and then go to send email.
Not sure to how do this. Please help. Thanks
Can you use a while loop with a counter?
declare #counter as int
set #counter = 0
while #counter <= 2
begin
#counter = #counter + 1
-- your code here
-- update #csvfilecount
if #csvfilecount < 16
begin
waitfor delay '00:05:00'
end
else
begin
send email
-- do you want to BREAK here?
end
end

cursor skips every other row

I have a cursor that works but skips every other record. My fetch next looks like this
OPEN DemandCur
While 1 = 1
BEGIN
FETCH NEXT FROM DemandCur INTO
#----,
#+++++
select #index = (select demand from TechCoDemand where Date = '2014-11-30')
IF #index <= 0 BREAK;
IF ##FETCH_STATUS <> 0 BREAK;
FETCH NEXT FROM DemandCur INTO
#---,
#++++
End
Close DemandCur
Deallocate DemandCur
I changed it to
FETCH NEXT
And it stopped skipping records but I get an error message after the query is done:
Msg 16916, Level 16, State 1, Line 121
A cursor with the name 'NEXT' does not exist.
Change your code to this....
OPEN DemandCur
FETCH NEXT FROM DemandCur INTO #----, #+++++
While ##FETCH_STATUS = 0
BEGIN
select #index = (select demand from TechCoDemand where Date = '2014-11-30')
IF #index <= 0 BREAK;
FETCH NEXT FROM DemandCur INTO #---, #++++
END
Close DemandCur
Deallocate DemandCur
As others have alluded to in the comments above, you're fetching twice within your while loop. While (ha!) you do need to "prime the pump" (so to speak) by fetching one row outside of the while loop first, here's an idiom that I like to use to avoid that entirely.
declare cursor foobar for
select ...
open foobar
while(1=1)
begin
fetch next from foobar into ...
if (##fetch_status <> 0)
break
--process results
end
close foobar
deallocate foobar
This has the benefit of only having to have one fetch statement to maintain but, more germane to this conversation, avoids your error entirely.

SQL WITH keyword inside CURSOR

Observing some strange behavior when using WITH keyword inside CURSOR:
WITH minuteList (aMinute) AS
(
SELECT #startTime UNION ALL
SELECT DATEADD(MINUTE, 1, aMinute)
FROM minuteList
WHERE aMinute < DATEADD(MINUTE, 9, #startTime)
)
SELECT * FROM minuteList
The above code works perfectly creating a table with one aMinute column and 10 datetime rows with 1 minute interval. However, the code below enters into an infinite loop printing only #startTime value endlessly.
DECLARE cursor1 CURSOR FOR
WITH minuteList (aMinute) AS
(
SELECT #startTime UNION ALL
SELECT DATEADD(MINUTE, 1, aMinute)
FROM minuteList
WHERE aMinute < DATEADD(MINUTE, 9, #startTime)
)
SELECT * FROM minuteList
OPEN cursor1
FETCH NEXT FROM cursor1 INTO #laterTime
WHILE ##FETCH_STATUS = 0 BEGIN
PRINT #laterTime
END
CLOSE cursor1;
DEALLOCATE cursor1;
Can someone explain what's happening and why the infinite loop occurs?
I have done a line-by-line analysis of your cursor call to explain why it goes into an infinite loop.
OPEN cursor1 // Opens your cursor
FETCH NEXT FROM cursor1 INTO #laterTime // Takes the first row returned by the
cursor and inserts it into the
variable #laterTime
WHILE ##FETCH_STATUS = 0 BEGIN // Checks if the next value has been
fetched and executes
the code inside the loop
PRINT #laterTime // Prints the current row
END // Ends the loop when FETCH_STATUS is
not 0 (when fetch fails).
CLOSE cursor1; // Closes the cursor.
The cause for the infinite loop is the fact that ##FETCH_STATUS is never changed because you have accessed only the first row from the cursor (the fetch has not failed because it has not been called more than once). After printing #laterTime, you need to fetch the next value of the cursor inside the loop. And only when that fetch fails will the loop terminate.
Consider this example as a reference.
Modified code will look like this:
OPEN cursor1
FETCH NEXT FROM cursor1 INTO #laterTime
WHILE ##FETCH_STATUS = 0 BEGIN
PRINT #laterTime
FETCH NEXT FROM cursor1 INTO #laterTime
END
CLOSE cursor1;

T-SQL Output Message During execution in SSMS

I have a simple query which loops and I want to see the PRINT messages during the execution. The query is something like this:
WHILE 1 = 1
BEGIN
WAITFOR DELAY '000:00:10'
PRINT 'here'
END
The PRINT 'here' does not output until I stop the process. However, I want to see it while it's running. Is this possible?
You can use RAISERROR with serverity 0 and the NOWAIT option
WHILE 1 = 1
BEGIN
WAITFOR DELAY '000:00:10'
RAISERROR ('here', 0, 1) WITH NOWAIT
END
I believe that the prints get buffered, releasing "chunks" as the buffer fills up.
try using raiserror:
How do I flush the PRINT buffer in TSQL?
Try this..
DECLARE #i INT = 1
WHILE ( #i <= 10)
BEGIN
--- do something
SELECT 'Completed ' + CAST(#i AS VARCHAR(50)) + ' : ' + CAST(GETDATE() AS VARCHAR(50));
SET #i = #i + 1
END
current suggestions don't work for SSMS 18 and above.
Print then raiserror(N'', 0, 1) seems to get around this.