Cursor never stops
-
21-01-2021 - |
Domanda
I appear to have made an error in this cursor and I can't seem to figure out what I have done wrong.
I've confirmed that the select
pulls back 2 rows. But when I pass it into the cursor to pick appear the string and I can extract the exact value I need. The two rows look something like the following...
|DATAIDONTWANT|...|DATAIDONTWANT|<|1|DATAIDONTWANT|<|2|DATAIDONTWANT|...|
|DATAIDONTWANT|...|DATAIDONTWANT|<|1|DATAIDONTWANT|<|2|DATAIDONTWANT|...|
The cursor appears to grab the 1st row and continually loop around never getting onto the next row or end the program.
declare
@clobstringP varchar(max),
@clobstring varchar(max);
declare SevenCursor cursor for
select [value] as ClobP
from string_split(@clobstring, '>')
where value like '%<|2|%';
open SevenCursor;
fetch next from SevenCursor into @clobstringP;
while @@FETCH_STATUS = 0
begin
insert into [database].dbo.tablestuff ( ValueP )
select file387
from (
select
RowId387 = row_number() over( order by ( select 1 ) )
,file387 = [value]
from string_split(@clobstringP, '|')
) a
where a.RowId387 = 6;
end;
close SevenCursor;
deallocate SevenCursor;
Can someone point me in the right direction?
Soluzione
As Peter has pointed out, your loop will never end since you don't do a fetch inside the loop. I prefer to have only one FETCH to maintain instead of two. So, my loop structure for a cursor is as follows:
WHILE 1 = 1
BEGIN
FETCH NEXT FROM OrdersCursor INTO @sales_person_id, @orderdate;
IF @@FETCH_STATUS <> 0
BREAK
--Whatever it is I'm doing inside the loop
END
A matter of taste which you prefer...
Altri suggerimenti
The cursor will loop infinitely unless and until @@fetchstatus = 0
. In order to reach that state, you need to proceed through the dataset. In order to do that, you should add fetch next from SevenCursor into @clobstringP;
to the inside of the begin ... end
block so that the cursor has something to iterate over.
It is perhaps prudent to editorialize a bit at this stage and recommend that you try to ditch the cursor entirely. Cursors are pretty nifty but are misused more often than not; and from your provided psuedo-code, it seems that perhaps you may be trying to fix X
when you could bypass to Y
.
I might suggestion taking the whole result set and string_split
-ing it into a sensible #temp_table
. When you've performed any necessary updates/deletes on this cached result set and verified it's suitable, try for a single insert into dbo.tablestuff ...
to succeed or fail based on batch evaluated rules. For example:
declare @pipe_delimited_rows table (
my_row varchar(max)
);
insert @pipe_delimited_rows ( my_row )
values
(N'|DATAIDONTWANT|...|DATAIDONTWANT|<|1|DATAIDONTWANT|<|2|DATAIDONTWANT|...|'),
(N'|DATAIDONTWANT|...|DATAIDONTWANT|<|1|DATAIDONTWANT|<|2|DATAIDONTWANT|...|');
drop table if exists #cache_results;
create table #cache_results (
id int identity not null primary key
,ClobP nvarchar(max)
);
insert #cache_results ( ClobP )
select ss.[value] as ClobP
from @pipe_delimited_rows pdr
cross apply string_split(pdr.my_row, '>') ss -- delimiting appropriately here, of course
where ss.[value] like '%<|2|%';
/* perform business logic to validate interim results here */
insert into [database].dbo.tablestuff ( ValueP )
select ClobP
from #cache_results;
Disclaimers
- The sample pseudo-code won't run sensibly as is. I'm kind of patching together from rev 1 of your OP. You'll of course need to delimit on the proper delimiter and perform the appropriate transformations to your live dataset.
- It's worth noting that there is NO way to enforce order-of-elements within string_split at this time.