While using cursor in SQL Server 2008 ,at which statement the values from tables are loaded into the cursor?
declare #sname nvarchar(50)
declare cur1 cursor
for
select sname from tstudent
open cur1
FETCH NEXT FROM cur1 INTO #sname
print #sname
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM cur1 INTO #sname
if ##FETCH_STATUS = 0
print #sname
END
CLOSE cur1
DEALLOCATE cur
When you OPEN a cursor, the cursor gets populated from DB using the query specified in DECLARE statement. More on this at MSDN
Related
I am trying to send one response back to an API from a SQL Server cursor.
The cursor calls a stored procedure that has a select in it.
declare db_cursor cursor for select
[item]
from someTable
open db_cursor;
fetch next from db_cursor into #item
while ##fetch_status = 0 begin
exec db..someStoredProcedure #item -- Prevent a select in this proc
fetch next from db_cursor into #item
end;
close db_cursor;
deallocate db_cursor;
select 'end cursor' -- Send this back to API
How can I prevent exec select from being returned to the parent procedure so that only end cursor is selected once the cursor is complete?
I know you can do this easily using the GUI in SSMS. But,is there a way to include all the articles with TSQL instead of doing them one by one using sp_addarticle?
My initial idea is returning all the tables names(using a sys query) and then using a loop to feed them to sp_addarticle. I'm wondering if there's a smarter way for example a built-in variable that I can assign 'all' to it?
This is how I did it
USE [DatabaseName]
DECLARE #name sysname
DECLARE #getid CURSOR
SET #getid = CURSOR FOR
-- Select all tables name
SELECT [name]
FROM [DataBaseName].[sys].[tables]
WHERE is_ms_shipped=0
-- While loop
OPEN #getid
FETCH NEXT
FROM #getid INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
-- add article
exec sp_addarticle #publication = #publication
,#article = #name
,#source_object = #name
,#del_cmd = 'NONE'
FETCH NEXT
FROM #getid INTO #name
END
CLOSE #getid
DEALLOCATE #getid
I have a table that stores names of stored procedures in my file structure. The idea is that the calling stored procedure will be given #in_Strings as a parameter; these are the display names of the stored procedures I want to execute.
Then, I want to search my table of stored procedures and execute the ones whose display names match with the inputted set.
For example, the calling stored procedure may be given an input set of strings 'foo', 'bar', and 'baz'. That means I want to be able to execute 'dbo.foo_sproc','dbo.bar_sproc', and 'dbo.baz_sproc'.
I am using SQL Server 2012. Any ideas?
BTW, my stored procedures table looks like this:
CREATE TABLE dbo.SPROCS
(
Display_Name NVARCHAR(256) NOT NULL,
SPROC_Name NVARCHAR(256) NOT NULL,
CreatedDateTime DATETIME2(2) NOT NULL DEFAULT GETUTCDATE()
)
You can use dynamic SQL, like in paqogomez's answer, but, unlike any other kind of names, procedure names can be parametrised in SQL Server, and so dynamic SQL is not necessary in this case.
For instance, if this was about a single procedure, you could read and execute the matching name using this simple method:
DECLARE #SPROC_Name nvarchar(256);
SELECT #SPROC_Name = SPROC_Name
FROM dbo.SPROCS
WHERE Display_Name = #in_string;
EXECUTE #SPROC_Name;
Just like that.
Since you are mentioning a set of strings, however, you will need a cursor to loop through the result set of matching procedure names and pass each name to the EXECUTE statement.
DECLARE #SPROC_Name nvarchar(256);
DECLARE procnames CURSOR
LOCAL FORWARD_ONLY STATIC READ_ONLY
FOR
SELECT #SPROC_Name = SPROC_Name
FROM dbo.SPROCS
WHERE ... /* condition involving Display_Name and #in_string */
;
OPEN procnames;
FETCH NEXT FROM procnames INTO #SPROC_Name;
WHILE ##FETCH_STATUS = 0
BEGIN
EXECUTE #SPROC_Name;
FETCH NEXT FROM procnames INTO #SPROC_Name;
END;
CLOSE procnames;
DEALLOCATE procnames;
A sql server example:
A cursor can loop through your result set and execute your stored procedures.
This (simple, but untested) script loops every sproc in the #in_strings variable.
CREATE PROCEDURE getSprocs #in_Strings varchar(max)
AS
BEGIN
DECLARE #sql varchar(max)
DECLARE db_cursor CURSOR FOR
SELECT SPROC_Name
FROM dbo.SPROCS
where sproc_name in (#in_Strings)
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
set #sql = 'exec ' + #name
exec #sql
FETCH NEXT FROM db_cursor INTO #name
END
CLOSE db_cursor
DEALLOCATE db_cursor
END
I have worked on SQL Server database. Now I have to work on a Sybase database (using a Squirrel client). This query is not working :
DECLARE #tableName VARCHAR(500);
DECLARE my_cursor CURSOR FOR
SELECT name
FROM sysobjects
WHERE type = 'U';
OPEN my_cursor;
FETCH NEXT FROM my_cursor INTO #tableName;
WHILE ##FETCH_STATUS = 0
BEGIN
//Do something here
FETCH NEXT FROM my_cursor;
END
CLOSE my_cursor;
DEALLOCATE CURSOR my_cursor;
It gives an error - Incorrect syntax near the keyword 'FROM'.
SQLState: ZZZZZ
ErrorCode: 156
Error occured in:
FETCH NEXT FROM my_cursor INTO #table_Name
Now this works fine in a SQL Server database (after I change the last line to DEALLOCATE my_cursor). Can anybody tell me where I am going wrong?
As Mitch points out the fetch syntax is:
fetch cursor_name [into fetch_target_list]
You also need to declare the cursor in a separate batch, this means you must put a "GO" after the declare statement. You will then find that your variable drops out of scope, so you'll need to move that so that it's after the "GO".
You also need to examine ##sqlstatus to see how successful the fetch was, rather than ##FETCH_STATUS which I think is MSSQL only.
DECLARE my_cursor CURSOR FOR
SELECT name
FROM sysobjects
WHERE type = 'U'
go
DECLARE #tableName VARCHAR(500)
set nocount on
OPEN my_cursor
FETCH my_cursor INTO #tableName
WHILE ##sqlstatus = 0
BEGIN
--Do something here
FETCH my_cursor INTO #tableName
print #tablename
END
CLOSE my_cursor
DEALLOCATE CURSOR my_cursor
And no semicolons needed at the end of lines in Sybase ASE.
DECLARE #tableName VARCHAR(500);
DECLARE my_cursor CURSOR FOR
SELECT name
FROM sysobjects
WHERE type = 'U';
OPEN my_cursor;
FETCH my_cursor INTO #tableName;
WHILE ##FETCH_STATUS = 0
BEGIN
//Do something here
FETCH my_cursor INTO #tableName;
END
CLOSE my_cursor;
DEALLOCATE CURSOR my_cursor;
Declare #tablename after the cursor.
First of all Squirrel supports go as a SQL batch separator. Go to menu item Session--> Session Properties---> 'SQL' Tab.
Scroll to bottom and set 'Statement Separator' as 'go' (quotes not needed) .
Then follow the previous answer . The DECLARE CUROSR can be the only SQL statement in a batch , hence you must insert go after it.
In the next batch re-declare any variables that were declared in earlier batch and will be referenced in second batch.
This should work. This is how I have been testing SQL code involving cursors for years.
I have a strange problem with my nested cursors and I have no idea what it's all about.
Here's my T-SQL code:
declare #dbname varchar(50)
declare #servername varchar(50)
declare srv cursor for select servername from test.dbo.servers
declare #str varchar(200)
truncate table test.dbo.temp
open srv
fetch next from srv into #servername
while ##fetch_status = 0
begin
set #str = 'Data Source='+#servername+';Integrated Security=SSPI'
declare db cursor for select name from opendatasource('SQLNCLI', #str).master.dbo.sysdatabases
open db
fetch next from db into #dbname
while ##fetch_status = 0
begin
insert test.dbo.temp (dbname, servername) values (#dbname, #servername)
fetch next from db into #dbname
end
fetch next from srv into #servername
close db
deallocate db
end
close srv
deallocate srv
It gives me next error message:
Incorrect syntax near '#str'.
[SQLSTATE 42000] (Error 102)
Looks like the problem is in giving the variable as a parameter to opendatasource function. But why? And how to avoid this problem?
You are correct that variables cannot be passed to OPENDATASOURCE. Instead You must use a literal instead. As much as we discourage using dynamic SQL, there are some cases that it is unavoidable. Try something like this:
declare #dbname varchar(50)
declare #servername varchar(50)
declare srv cursor for select servername from test.dbo.servers
declare #str varchar(200)
declare #sql nvarchar(MAX)
truncate table test.dbo.temp
open srv
fetch next from srv into #servername
while ##fetch_status = 0
begin
SET #sql = N'
declare db cursor for select name from opendatasource(''SQLNCLI'', ''Data Source='+#servername+';Integrated Security=SSPI'').master.dbo.sysdatabases
open db
fetch next from db into #dbname
while ##fetch_status = 0
begin
insert test.dbo.temp (dbname, servername) values (#dbname, #servername)
fetch next from db into #dbname
end
close db
deallocate db
'
EXEC sp_executesql
#sql,
N'#dbname varchar(50),
#servername varchar(50)',
#dbname,
#servername
fetch next from srv into #servername
end
close srv
deallocate srv
If you need to use nested cursors, you are doing something wrong. There are very few reasons to use a cursor instead of some other set-based operation, and using a cursor within a cursor is like the ultimate SQL Server anti-pattern.
For your inner cursor, you could change it to use the undocumented sp_msforeachdb function (which apparently creates a cursor behind the scenes):
open srv
fetch next from srv into #servername
while ##fetch_status = 0
begin
EXEC sp_msforeachdb '
Data Source='+#servername+';Integrated Security=SSPI
insert test.dbo.temp (dbname, servername) values (?, #Servername)'
fetch next from srv into #servername
end
close srv
deallocate srv
You may need to enclose the ? in single quotes and escape them, like:
EXEC sp_msforeachdb 'insert test.dbo.temp (dbname, servername) values (''?'', #Servername)