GO
SET NOCOUNT ON;
DECLARE
#idAdvertisements int,
#Name nvarchar(255),
#Description nvarchar(500),
#DepartureDate datetime,
#Cities_idCities int,
#Areas_idAreas int,
#Countries_idCountries int,
#Agencies_idAgencies int,
#Url nvarchar(1000),
#Price decimal(6, 2),
#HollidayDuration int,
#BookingDate datetime;
DECLARE ad_cursor CURSOR
FOR SELECT idAdvertisements
,Name
,Description
,DepartureDate
,Cities_idCities
,Areas_idAreas
,Countries_idCountries
,Agencies_idAgencies
,Url
,Price
,HollidayDuration
,BookingDate
FROM Advertisements;
OPEN ad_cursor;
FETCH NEXT FROM ad_cursor
INTO #idAdvertisements
,#Name
,#Description
,#DepartureDate
,#Cities_idCities
,#Areas_idAreas
,#Countries_idCountries
,#Agencies_idAgencies
,#Url
,#Price
,#HollidayDuration
,#BookingDate;
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT ' ';
PRINT #idAdvertisements;
--PRINT #Name;
--PRINT #Description;
--PRINT #DepartureDate;
--PRINT #Cities_idCities;
END
CLOSE ad_cursor;
But I always get 1, 1, 1, 1, 1. Data are always the same.
SELECT statement is OK. I don't understand why. Can someone see the problem?
cursors are Evil.. eVIL.. eVil.. stay away from them
Now, here is the issue - you are not moving the cursor forward..
DECLARE ad_cursor CURSOR
FOR SELECT idAdvertisements, Name, Description, DepartureDate, Cities_idCities, Areas_idAreas,
Countries_idCountries, Agencies_idAgencies, Url, Price, HollidayDuration, BookingDate FROM Advertisements;
OPEN ad_cursor;
FETCH NEXT FROM ad_cursor
INTO #idAdvertisements, #Name, #Description, #DepartureDate, #Cities_idCities, #Areas_idAreas,
#Countries_idCountries, #Agencies_idAgencies, #Url, #Price, #HollidayDuration, #BookingDate;
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT ' ';
PRINT #idAdvertisements;
--PRINT #Name;
--PRINT #Description;
--PRINT #DepartureDate;
--PRINT #Cities_idCities;
FETCH NEXT FROM ad_cursor
INTO #idAdvertisements, #Name, #Description, #DepartureDate, #Cities_idCities, #Areas_idAreas,
#Countries_idCountries, #Agencies_idAgencies, #Url, #Price, #HollidayDuration, #BookingDate;
END
CLOSE ad_cursor;
The code as you have it here will loop infinitely. You need another FETCH at the end of the body of the WHILE loop, otherwise ##FETCH_STATUS will never change.
OPEN ad_cursor;
FETCH NEXT FROM ad_cursor
INTO #idAdvertisements, #Name, #Description, #DepartureDate, #Cities_idCities, #Areas_idAreas,
#Countries_idCountries, #Agencies_idAgencies, #Url, #Price, #HollidayDuration, #BookingDate;
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT ' ';
PRINT #idAdvertisements;
--PRINT #Name;
--PRINT #Description;
--PRINT #DepartureDate;
--PRINT #Cities_idCities;
FETCH NEXT FROM ad_cursor
INTO #idAdvertisements, #Name, #Description, #DepartureDate, #Cities_idCities, #Areas_idAreas,
#Countries_idCountries, #Agencies_idAgencies, #Url, #Price, #HollidayDuration, #BookingDate;
END
CLOSE ad_cursor;
You have add fetch the next row, just before the END
Related
I'm sure there's a simple explanation. I'm trying to print out the Max ID for all tables with an Identity column.
The TSQL code below seems to run fine in the sense that the Results window contains cells with values, but the Messages window does not show: Table1 Row Count = 99
Seems as if the #Result variable is NULL when it gets to the PRINT command.
Am I missing something obvious or is the OUTPUT command working differently than I expect?
DECLARE #TABLE VARCHAR(100)
DECLARE #FIELD VARCHAR(100)
DECLARE #SQL NVARCHAR(300)
DECLARE #result BIGINT
DECLARE CUR CURSOR FOR
SELECT
[table] = t.name,
[colname] = c.name
FROM sys.schemas AS s
INNER JOIN sys.tables AS t
ON s.[schema_id] = t.[schema_id]
INNER JOIN sys.identity_columns c ON c.object_id = t.[object_id]
OPEN CUR
FETCH NEXT FROM CUR INTO #TABLE, #FIELD
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = 'SELECT MAX([' + #FIELD + ']) FROM [' + #TABLE + ']'
EXEC sp_executesql #SQL,
N'#result int OUTPUT',
#result OUTPUT
PRINT #TABLE + ' Row Count = ' + CONVERT(nvarchar, #result)
--NOTHING SEEMS TO BE PRINTED HERE
FETCH NEXT FROM CUR INTO #TABLE, #FIELD
END
CLOSE CUR
DEALLOCATE CUR
I have a following situation.
I have a table with trigger for insert.
When I insert a row in it, from this trigger I want to insert some rows into a second table.
For each of these rows I want to do it in it's own transaction in case something go wrong.
I want to have original row in first table and all rows (these withous errors) in the second.
A little code to reproduce:
create table test(id int primary key identity(1,1),name nvarchar(10))
create table test2(id int primary key identity(1,1),
state char(1) check (state in ('a','b')))
go
create trigger test_trigger on test for insert
as
begin
declare #char char(1)
declare curs cursor for (
select 'a'
union
select 'c'
union
select 'b')
open curs
fetch next from curs into #char
while ##FETCH_STATUS = 0
begin
begin try
begin transaction
insert into test2(state)
select #char
commit
end try
begin catch
print 'catch block'
rollback
end catch
fetch next from curs into #char
end
close curs
deallocate curs
end
go
insert into test(name) values('test')
select * from test
select * from test2
go
drop table test
drop table test2
So for the sample data from this snippet, I want to have a row with 'test' in test table and two rows in the test2 table ('a' and 'b').
How can I write a code for that?
Looks like finally I got it to work.
Corrected trigger code:
create trigger test_trigger on test for insert
as
begin
declare #char char(1)
set xact_abort off
declare curs cursor for (
select 'a'
union
select 'c'
union
select 'b')
open curs
fetch next from curs into #char
while ##FETCH_STATUS = 0
begin
save transaction t
begin try
insert into test2(state)
select #char
end try
begin catch
print 'catch block'
rollback transaction t
end catch
fetch next from curs into #char
end
close curs
deallocate curs
end
am using cursor to update my null column but it is not updating
Declare #Itemcode as varchar(30)
Declare #SLV as varchar(20)
declare cursor1 cursor for
Select Itemcode ,U_SLV from oitm_Clone where sapitem is null and u_slv is null
open cursor1
fetch next FROM cursor1 INTO #Itemcode ,#SLV
WHILE ##FETCH_STATUS = 0
begin
if #SLV is null
begin
declare #sql1 as varchar(max)
set #sql1 = 'Update [dbo].oitm_Clone set sapitem ='''+ #Itemcode +''' where ItemCode='''+ #Itemcode +''' and U_SLV ='''+ #SLV +''''
print #sql1
execute (#sql1)
end
FETCH NEXT FROM cursor1 INTO #Itemcode ,#SLV
end
CLOSE cursor1
DEALLOCATE cursor1
I think you don't need a cursor to do this update. Try this simple update which has the same logic of your cursor with much improved performance.
Update [dbo].oitm_Clone
Set sapitem = itemcode
Where sapitem is null and u_slv is null
try to use this
WHILE ##FETCH_STATUS <> -1
instead of
WHILE ##FETCH_STATUS = 0
hope it will help you
regards
Before I get any militant cursor-bashing, let me say that I'm trying to use nested cursors to do something I only need to do once, but if I ran the operative stored procedure once for each user and agency I have to do it a few hundred times.
I thought a nested cursor in this case would save me some work, however, when I run this script it goes through the outer cursor only once, while the inner works just fine for that run. In the test case, the outer cursor set consists of two rows, and the inner one has about fifty. It goes through the first row of the outer cursor, and all fifty of the inner, but then it's done.
As you can see, I am saving off the result of the outer fetch (the '##fetch_status') so it doesn't interfere with the inner cursor.
I can't see what the problem is (obviously). Can anyone see what I can't?
declare #fetch_user int
declare #fetch_agency int
declare user_cursor cursor for
select upn from #users
open user_cursor
fetch next from user_cursor into #upn
select #fetch_user = ##fetch_status
while #fetch_user = 0
begin
declare agency_cursor cursor for
select agency, subagency from agency_system where system_id = 1
open agency_cursor
fetch next from agency_cursor into #agency, #subagency
select #fetch_agency = ##fetch_status
while #fetch_agency = 0
begin
select #upn, #agency, #subagency
EXEC AddUserToAgencyInRole
#upn
, #agency
, #subagency
, #system_id
, #role_id
, #response output
fetch next from agency_cursor into #agency, #subagency
select #fetch_agency = ##fetch_status
end
close agency_cursor
deallocate agency_cursor
fetch next from user_cursor into #upn
select #fetch_user = ##fetch_status
end
close user_cursor
deallocate user_cursor
The code looks like it should work. Throw in a count at the start:
select count(*) from #users
to double check the number of rows in #users ?
I'm not sure about troubleshooting the nested cursor other than that there is a way to get rid of it and have only one cursor.
Make this select statement using a cross-join:
SELECT u.upn, a.agency, a.subagency
FROM #users u, agency_system a
WHERE a.system_id = 1
Use that as your cursor definition. It should have every combination of user and agency/subagency.
I agree with Andomar it should work. This test case goes through the outer loop 4 times and the inner loop twice per iteration. (Which matches the number of rows in the respective tables)
set nocount on
DECLARE #upn INT, #agency INT, #subagency INT
CREATE TABLE #users (upn INT)
insert into #users select 1 union select 2 UNION select 3 UNION select 4
CREATE TABLE #agency_system(
agency INT,
subagency INT,
system_id INT)
insert into #agency_system
select 1,1,1 UNION select 2,2,1
declare #fetch_user int
declare #fetch_agency int
declare user_cursor cursor for
select upn from #users
open user_cursor
fetch next from user_cursor into #upn
select #fetch_user = ##fetch_status
while #fetch_user = 0
begin
PRINT 'In Outer While Loop'
declare agency_cursor cursor for
select agency, subagency from #agency_system where system_id = 1
open agency_cursor
fetch next from agency_cursor into #agency, #subagency
select #fetch_agency = ##fetch_status
while #fetch_agency = 0
begin
PRINT 'In Inner While Loop'
fetch next from agency_cursor into #agency, #subagency
select #fetch_agency = ##fetch_status
end
close agency_cursor
deallocate agency_cursor
fetch next from user_cursor into #upn
select #fetch_user = ##fetch_status
end
close user_cursor
deallocate user_cursor
drop TABLE #users
drop TABLE #agency_system
I appreciate all the responses.
I ended up eliminating the outer cursor and just manually running the inner one. This saved me from manually entering 393 separate entries. I just had to run the script three times.
I have some PLSQL code which loops through some logic:
FOR I in cur1
LOOP
SELECT value1, value2
FROM db1..table1 t1
END LOOP;
Can anyone explain to me the syntax for doing this in TSQL?
This is a generic loop in a standar TSQL Cursor. But try to avoid Cursors when possible. They Have very bad performance.
DECLARE #somevariable VARIABLE_TYPE_HERE
DECLARE #sampleCursor CURSOR
SET #sampleCursor = CURSOR FOR
SELECT somefield... from bla bla bla...
OPEN #sampleCursor
FETCH NEXT
FROM #sampleCursor INTO #somevariable
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #somevariable
FETCH NEXT
FROM #sampleCursor INTO #somevariable
END
CLOSE #sampleCursor
DEALLOCATE #sampleCursor
There is no FOR in T-SQL. An example with WHILE:
DECLARE Employee_Cursor CURSOR FOR
SELECT EmployeeID, Title
FROM AdventureWorks2008R2.HumanResources.Employee
OPEN Employee_Cursor;
FETCH NEXT FROM Employee_Cursor;
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM Employee_Cursor;
END;
CLOSE Employee_Cursor;
DEALLOCATE Employee_Cursor;
For more information: http://msdn.microsoft.com/en-us/library/ms178642.aspx