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.
Related
In attempting to clean up my database, I have managed to identity a list of stored procedures that aren't being used. I want to mark these for deletion, adding the post-fix "_DELETE" to all of these in one script. Can anyone advise me on how to go about this please? Thank you.
Try to use cursor for this purpose:
DECLARE #mockupTable TABLE(ID INT IDENTITY, SPName VARCHAR(100));
INSERT INTO #mockupTable VALUES
('old_proc_name1')
,('old_proc_name2')
,('old_proc_name3')
DECLARE #name VARCHAR(50) = 'deleted'
DECLARE #newName VARCHAR(50)
DECLARE db_cursor CURSOR FOR
SELECT SPName FROM #mockupTable
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #newName = CONCAT(#name, '_DELETED')
--PRINT #newname
EXEC sp_rename #name, #newname
FETCH NEXT FROM db_cursor INTO #name
END
CLOSE db_cursor
DEALLOCATE db_cursor
Assuming you already have the names for your procedures you can just substitute them into your cursor definition below:
DECLARE ProcCursor CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT Name = CONCAT(QUOTENAME(s.name), '.', QUOTENAME(p.name)),
[NewName] = CONCAT(p.name, '_DELETE')
FROM sys.procedures AS p
INNER JOIN sys.schemas AS s
ON s.schema_id = p.schema_id
WHERE p.object_id IN
( OBJECT_ID('dbo.SomeProc', 'P'),
OBJECT_ID('dbo.SomeProc2', 'P'),
OBJECT_ID('dbo.SomeProc3', 'P')
);
DECLARE #Name NVARCHAR(776), #NewName SYSNAME;
OPEN ProcCursor;
FETCH NEXT FROM ProcCursor INTO #Name, #NewName
WHILE (##FETCH_STATUS = 0)
BEGIN
EXECUTE sp_rename #Name, #NewName, 'OBJECT';
FETCH NEXT FROM ProcCursor INTO #Name, #NewName
END
CLOSE ProcCursor;
DEALLOCATE ProcCursor;
It is worth noting that this is one of the very few scenarios where I would advocate using a cursor, but as above when using a cursor you should always ensure you explicitly declare the simplest cursor possible (e.g. LOCAL STATIC READ_ONLY FORWARD_ONLY). By telling SQL Server your cursor will be static, only used locally, and only ever read and only in one direction, your cursor will be much faster than if you don't and SQL Server has to work on the assumption that anything could happen with the cursor. On a small scale like this it is unlikely to make a tangible difference, but on larger sets it can make a considerable difference.
For further reading see What impact can different cursor options have? - The conclusion is actually that I should have used LOCAL FAST_FORWARD, rather than the options I did use. I have left these in though, as the difference is negligible and I found using all 4 easier to remember and displays intent clearer.
To re-iterate what has been stated in comments, it really is a good idea to use version control on your databases, that way you don't need to mark anything for deletion, you can just delete it, and still retain the definition in your source control. If you can't use source control for whatever reason, DDL triggers can provide rudimentary change tracking
I'm currently learning SQL and trying to think of exercises for myself and I can't seem to make this one work even though it seems simple:
I'm trying to run a cursor through all the filtered tables within my db so that then I could pass that table name to a variable which will be used within a DynamicSQL inside the cursor. The end result should be all values from every column that has the column 'empid' in them.
However, the message returns as "Commands completed successfully" but I get to see no results despite my select statement.
I'm trying to run something like this:
declare #tablename nvarchar(200);
declare #empid int;
declare #sql nvarchar(200) = N'select * from ' + #tablename + N' where empid = ' +#empid;
declare tablecursor cursor for select table_name from information_schema.tables where col_length(table_name, 'empid') is not null;
open tablecursor;
fetch next from tablecursor into #tablename;
while ##fetch_status = 0
begin
execute sp_executesql #sql, 825
fetch next from tablecursor into #tablename;
end
close tablecursor;
deallocate tablecursor;
I've been searching everywhere for answers to make this work but can't find anything. I've tried putting into a stored procedure and then executing it from there but that didn't work either.
Help would be highly appreciated.
DECLARE #SQL Should be outside but assigning the Variable inside the while loop
SET #SQL = N'SELECT * FROM ' + #tableName
Should be in while loop.
The other thing is to increase the length of #SQL Variable.
Thank you kindly for the help. After I listened to your advice I've encountered more errors but at least for these I was able to find answers online. What I also learnt is that you can't have your sql string in quotes when you execute it as that will make SSMS treat #SQL as an actual string and not a variable. I've managed to get it working and my code now looks something like this:
create proc cdr #empid nvarchar(5) as
declare #tablename nvarchar(200);
declare tablecursor cursor for select table_name from information_schema.tables where col_length(table_name, 'empid') is not null;
open tablecursor;
fetch next from tablecursor into #tablename;
declare #sql nvarchar(max)
while ##fetch_status = 0
begin
set #sql = N'select * from ' + #tablename + N' where empid = ' + #empid;
execute sp_executesql #sql
fetch next from tablecursor into #tablename;
end
close tablecursor;
deallocate tablecursor;
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 multiple databases in my SQL Server. All databases are the same in structure but have different data. These databases are used to store sensor data so each sensor has it's own seperate DB in the SQL Server.
I want a query to Select the Database name and number of records in a specific table of each DB.
I tried with a cursor. I get error saying the name {query} is not a valid identifier. My Cursor is as follows:
Declare #dbname Varchar (50), #sql Varchar(1000)
Declare db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name LIKE 'EP505-%' -- All sensors of EP505
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql= 'SELECT Count(*) FROM [' + #dbname + '].dbo.TimeLine'
EXEC #sql
FETCH NEXT FROM db_cursor INTO #dbname
END
CLOSE db_cursor
DEALLOCATE db_cursor
In the output I require the db name and the number of records for the TimeLine table.
What's the best way to achieve what I am trying.
Use parentheses when executing a SQL query string like so:
EXEC (#sql). Without parentheses, SQL Server will interpret #sql as a stored procedure or user-defined function.
your attempt looks quite good so far.
Please try adding a fetch next below the exec-line and try putting the #SQL variable after the exec brackets. That worked in my SQL Server environment.
hope this helps
br
Patrik
You can use sp_executeSQL to execute your dynamic query instead of exec statement which will help you to solve your issue
Here is the modified version
Declare #dbname Varchar (50), #sql nVarchar(1000)
Declare db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name LIKE 'kodyaz' -- All sensors of EP505
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #dbname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql= N'SELECT Count(*) FROM [' + #dbname + '].dbo.Kontaktpersonen'
exec sp_executesql #sql
FETCH NEXT FROM db_cursor INTO #dbname
END
CLOSE db_cursor
DEALLOCATE db_cursor
I change #sql data type to nvarchar() and use
exec sp_executesql #sql
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