Adding the postfix "_DELETE" to all stored procedures identified as not being used - sql-server

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

Related

Can't query and put data inside a cursor when using variable inside the query

I have to put a result of a query (single column and value is being pulled) into a variable. I'm trying to use a cursor however I choose the database to query based on a variable here is my query
SELECT productName, price FROM #ShopName.dbo.Products WHERE ProductName = #ProductName
#ShopName variable is being pulled from the database first and assigned to the variable using a cursor. #ProductName variable is being populated by an input parameter coming from API. I have to get ProductName from a specific database (there are multiple databases with products), but the query above throws syntax errors. Additionally when I tried ad hoc query assigned to a variable:
SET #Sql = N'SELECT productName, price FROM ' + QUOTENAME(#ShopName) + '.dbo.Products WHERE ProductName = ' + #ProductName
It doesn't allow to use it in
DECLARE cursorT CURSOR
FOR
#Sql
This throws Incorrect syntax near '#Sql', Expecting '(', SELECT, or WITH
Is there any way to make it possible to use that query in cursor while using the variable with database name in it?
Cursors should be right at the bottom of your bag of techniques, used sparingly and with great care, only when necessary. I can't tell if it's necessary in your case, there's not enough code to know. But I wanted to get that out before continuing.
As a point of purely academic interest, yes, there are some ways you can do this. Two main ways:
Declare a cursor in the dynamic SQL, as Dale suggested. You can still use the cursor in static code which follows the declaration if the cursor is global.
Use dynamic SQL to drop the results into something with scope outside of the dynamic sql, like a temp table. The cursor over the temp table.
1 is just bad. It is likely to result in code which is extremely difficult to understand in future. I include it for curiosity only. 2 is reasonable.
Examples:
-- some dummy schema and data to work with
create table t(i int);
insert t values(1), (2);
-- option 1: declare a cursor dynamically, use it statically (don't do this)
declare #i int;
exec sp_executesql N'declare c cursor global for select i from t';
open c;
fetch next from c into #i;
while (##fetch_status = 0)
begin
print #i;
fetch next from c into #i;
end
close c;
deallocate c;
-- option 2: dynamically dump data to a table, eg a temp table
create table #u(i int);
exec sp_executesql N'insert #u (i) select i from t';
declare c cursor local for select i from #u;
declare #i int;
open c;
fetch next from c into #i;
while (##fetch_status = 0)
begin
print #i;
fetch next from c into #i;
end
close c;
deallocate c;

Use of cursor in SQL

I want to know what is the use of cursor? i search on google and i read that cursor is used for manipulate data like in this example cursor is use .. in this example the select statement Select firstName, lastName FROM myTable returns rows
and when i execute whole query with cursor then this returns same as select statement return so what is the difference? we may use only select instead of cursor? here cursor what is the use ? can anyone explain please in simple words
DECLARE #fName varchar(50), #lName varchar(50)
DECLARE cursorName CURSOR -- Declare cursor
LOCAL SCROLL STATIC
FOR
Select firstName, lastName FROM myTable
OPEN cursorName -- open the cursor
FETCH NEXT FROM cursorName
INTO #fName, #lName
PRINT #fName + ' ' + #lName -- print the name
WHILE ##FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM cursorName
INTO #fName, #lName
PRINT #fName + ' ' + #lName -- print the name
END
CLOSE cursorName -- close the cursor
DEALLOCATE cursorName -- Deallocate the cursor
Many DBA's and developers have love/hate relationship with Cursors. Some will tell you not to use it, others that there is no danger and you can use it. As with many other tools, a cursor is just another tool to be used on some specific scenarios, correctly used can be an awesome tool. But incorrectly used can cause big performance issues.
Cursors work on a row basis and are a perfect sample of the RBAR "Row By Agonizing Row" instead of sets-based operations where tsql shines. The sample you provided is a really bad sample of correct cursor usage, yes, it can show you how a cursor works, but as you commented, that same action can be done with a simple SELECT.
If you do a quick search on your prefered search engine will find lot of good references about cursors, here are some to read:
https://www.brentozar.com/sql-syntax-examples/cursor-example/
RBAR vs. Set based programming for SQL
https://www.red-gate.com/simple-talk/sql/t-sql-programming/rbar-row-by-agonizing-row/

I need a cursor, how can I do this efficiently without locks

I have a table that has list of stored procedures.
I am using a cursor to then loop through and call and capture the result of each stored procedure (they all return 0 or 1).
So I have:
DECLARE #PROC_ID INT,
#PROC_NAME VARCHAR(50)
SELECT *
INTO #MY_PROCS
FROM TABLE_PROCS
DECLARE MY_CURSOR CURSOR FOR
SELECT PROC_ID, PROC_NAME
FROM TABLE_PROCS
OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO #PROC_ID, #PROC_NAME
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #PROC_RESULT = .......
UPDATE #MY_PROCS SET PROC_RESULT = #PROC_RESULT WHERE PROC_ID = #PROC_ID
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
DROP TABLE #MY_PROCS
I was reading on cursors, and read I should be setting it as READ ONLY and NO LOCK if possible.
Also, should I be using a table variable instead of a temp table?
Is it possible to do this w/o a cursor?
The most efficient cursor is going to be, at least in all of my testing:
DECLARE MY_CURSOR CURSOR
LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR ...
Now, it's impossible for us to know if you can do this without a cursor. You've conveniently left out the only information we could have used to tell you that. It seems you are calling a procedure for each call, but you can't be doing that with SELECT. And then you update a table with the result, but you drop the table.
So you have two tables, one of which you want to update with values from the other and they share a common key. Here you go:
update [m]
set proc_id = t.proc_id
from #MY_PROCS as [m]
inner join TABLE_PROCS as [t]
on m.proc_id = t.proc_id

Could this cursor be optimized or rewritten for optimum performance?

There is a need to update all of our databases on our server and perform the same logic on each one. The databases in question all follow a common naming scheme like CorpDB1, CorpDB2, etc. Instead of creating a SQL Agent Job for each of the databases in question (over 50), I have thought about using a cursor to iterate over the list of databases and then perform some dynamic sql on each one. In light of the common notion that cursors should be a last resort; could this be rewritten for better performance or written another way perhaps with the use of the undocumented sp_MSforeachdb stored procedure?
DECLARE #db VARCHAR(100) --current database name
DECLARE #sql VARCHAR(1000) --t-sql used for processing on each database
DECLARE db_cursor CURSOR FAST_FORWARD FOR
SELECT name
FROM MASTER.dbo.sysdatabases
WHERE name LIKE 'CorpDB%'
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #db
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = 'USE ' + #db +
' DELETE FROM db_table --more t-sql processing'
EXEC(#sql)
FETCH NEXT FROM db_cursor INTO #db
END
CLOSE db_cursor
DEALLOCATE db_cursor
Cursors are bad when they are used to tackle a set-based problem with procedural code. I don't think a cursor is necessarily a bad idea in your scenario.
When operations need to be run against multiple databases (backups, integrity checks, index maintenance, etc.), there's no issue with using a cursor. Sure, you could build a temp table that contains database names and loop through that...but it's still a procedural approach.
For your specific case, if you're not deleting rows in these tables based on some WHERE clause criteria, consider using TRUNCATE TABLE instead of DELETE FROM. Differences between the two operations explained here. Note that the user running TRUNCATE TABLE will need ALTER permission on the affected objects.
This will collect the set of delete statements and run them all in a single sequence. This is not necessarily going to be better performance-wise but just another way to skin the cat.
DECLARE #sql NVARCHAR(MAX); -- if SQL Server 2000, use NVARCHAR(4000)
SET #sql = N'';
SELECT #sql = #sql + N';DELETE ' + name + '..db_table -- more t-sql'
FROM master.sys.databases
WHERE name LIKE N'CorpDB%';
SET #sql = STUFF(#sql, 1, 1, '');
EXEC sp_executesql #sql;
You may consider building the string in a similar way inside your cursor instead of running EXEC() inside for each command. If you're going to continue using a cursor, use the following declaration:
DECLARE db_cursor CURSOR
LOCAL STATIC FORWARD_ONLY READ_ONLY
FOR
This will have the least locking and no unnecessary tempdb usage.

Can I use MS SQL syntax in Sybase?

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.

Resources