EXEC within the TRY...CATCH block - sql

I am trying to drop all the tables in the database with the following script:
WHILE EXISTS(SELECT * FROM sys.tables where is_ms_shipped = 0)
BEGIN
EXEC sp_MSforeachtable 'DROP TABLE ?'
END
I am getting lots of errors because of the foreign key constraints. But that is fine, tables are dropped anyway. I would like to get rid of the error messages with the following script.
WHILE EXISTS(SELECT * FROM sys.tables where is_ms_shipped = 0)
BEGIN
BEGIN TRY
EXEC sp_MSforeachtable 'DROP TABLE ?';
END TRY
BEGIN CATCH
END CATCH
END
This script just runs forever trying to drop the first table.
What am I doing wrong?

I'm not sure what's wrong with your query, but I've dropped tables using a cursor like this:
DECLARE #name as varchar(100)
DECLARE MyCursor CURSOR FAST_FORWARD FOR
SELECT name FROM sys.tables
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
execute('drop table ' +#name)
FETCH NEXT FROM MyCursor INTO #name
END
CLOSE MyCursor
DEALLOCATE MyCursor

Related

Cursor within a cursor for database dependent permissions

It would seem that my code should work, however testing indicates that all the results from the inner cursor are based on the current database at execution of the script and not dependent upon the USE statement within the script.
WHAT DID I FORGET?
DECLARE #Debug BIT = 1
DECLARE #newgrp VARCHAR(100) = 'ChangeTrakingViewableRole'
DECLARE #obj VARCHAR(100)
DECLARE #tsql VARCHAR(900)
DECLARE #tsql2 VARCHAR(900)
DECLARE #msg VARCHAR(900)
DECLARE #SchName VARCHAR(55)
DECLARE #TblName sysname
IF #Debug = 'TRUE' PRINT 'Debuging ON'
IF COALESCE(#newgrp,'') = ''
BEGIN
PRINT 'There was no DatabaseRole, User or Group Specified to take the place of the Public Role'
SET NOEXEC ON
END
ELSE
BEGIN
DECLARE DbCursor CURSOR FOR
SELECT 'USE '+DB_NAME(database_id) FROM sys.change_tracking_databases
OPEN DbCursor
FETCH NEXT FROM DbCursor INTO #obj
WHILE ##Fetch_Status = 0
BEGIN
SET #tsql2 = #obj+'; '
RAISERROR (#tsql2, 0, 1) WITH NOWAIT
EXEC sp_sqlexec #tsql2
-----------Commands within this next section are all database dependent
BEGIN --GRANT [VIEW CHANGE TRACKING] TO Change Tracking Enabled Tables
IF NOT EXISTS (SELECT name FROM sys.database_principals where name = #newgrp)
BEGIN
SET #tsql = N'CREATE ROLE '+#newgrp+' AUTHORIZATION [dbo]'
IF #Debug = 'TRUE'
BEGIN
SET #Msg = #tsql
RAISERROR (#Msg, 0, 1) WITH NOWAIT
END
ELSE
BEGIN
EXEC sp_sqlexec #tsql
END
END
DECLARE TblCursor CURSOR FOR
SELECT sch.name, tbl.name
FROM sys.change_tracking_tables chg
JOIN sys.tables tbl ON chg.object_id=tbl.object_id
JOIN sys.schemas sch ON tbl.schema_id=sch.schema_id
ORDER BY sch.name, tbl.name
OPEN TblCursor
FETCH NEXT FROM TblCursor INTO #SchName,#TblName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #tsql = 'GRANT VIEW CHANGE TRACKING ON ['+#SchName+'].['+#TblName+'] TO '+#newgrp
IF #Debug = 'TRUE'
BEGIN
SET #Msg = #tsql
RAISERROR (#Msg, 0, 1) WITH NOWAIT
END
ELSE
BEGIN
EXEC sp_sqlexec #tsql
END
FETCH NEXT FROM TblCursor INTO #SchName,#TblName
END
CLOSE TblCursor
DEALLOCATE TblCursor
END
FETCH NEXT FROM DbCursor INTO #obj
END
CLOSE DbCursor
DEALLOCATE DbCursor
END
The USE statements in your outer cursor are not doing anything for the statements generated aftwerward because they're being executed independently. When your outer cursor executes the USE it is just valid for the scope of the first EXEC sp_sqlexec call; it doesn't change the database context of the overall script. The context under which the rest of your script runs is still that of the overall script, meaning those statements will get run in the current database every time.
Bascially, you need to change this to generate a single script with the entirety of what you want to execute within the dynamic db context top to bottom, with the USE at the top, and then execute that whole thing in a single call to EXEC or sp_executesql.

Delete multiple records from table through cursor in sql server

there are number of test IP's which I would like to remove through system defined sp
exec sp_delete_firewall_rule from sys.firewall_rules table in sql server
I am using below cursor but its not working
declare #name nvarchar(max)
declare cur CURSOR LOCAL for
select #name from sys.firewall_rules where [name] like '%TestIP%'
open cur
fetch next from cur into #name
while ##FETCH_STATUS = 0 BEGIN
exec sp_delete_firewall_rule #name
fetch next from cur into #name
END
close cur
deallocate cur
It worked for me, you just need to change a couple of things in your code.
In the select list include the table ColumnName [name] instead of variable. You did not pass any value to the variable so this gives a NULL result.
Include SP parameter while executing exec sp_delete_firewall_rule #name = #name1;
I have these IP’s in my firewall rules:
With the below code I am deleting the IP’s which has a name like TestIP1.
DECLARE #name1 nvarchar(128);
DECLARE MyCursor CURSOR FOR
SELECT [name] from sys.firewall_rules where [name] like '%TestIP1%';
OPEN MyCursor;
FETCH FROM MyCursor into #name1
WHILE ##FETCH_STATUS = 0 BEGIN
EXEC sp_delete_firewall_rule #name = #name1 ;
FETCH next from MyCursor into #name1
END
CLOSE MyCursor;
DEALLOCATE MyCursor;
GO
Now the result shows only 1 IP which is not included in the above delete list.

Create an ms sql query to get data from tables belonging to different schemas

I have a table named 'tbl_user' and this table exists under many schemas for example :
schema1.tbl_user
schema2.tbl_user
and so on. I would like to union all the data in these tables and get a single result and I cannot use any programming language because the environment I need to run it doesn't allow for it. Is there a way to accomplish this on sql server 2008 using stored procedures?
Edit : There are over a thousand schemas and schemas can be added and deleted as time goes.
using cursor, create the query dynamic and execute at when completed.
You can add additional filter if you want to filter out the schema.
DECLARE #NAME VARCHAR(100)
DECLARE #SQL NVARCHAR(300)
DECLARE #TABLE_NAME NVARCHAR(300)='userMaster'
DECLARE CUR CURSOR FOR
SELECT S.name
from sys.schemas s
inner join sys.sysusers u
on u.uid = s.principal_id
order by s.name
OPEN CUR
FETCH NEXT FROM CUR INTO #NAME
WHILE ##FETCH_STATUS = 0
BEGIN
IF (EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA =#NAME
AND TABLE_NAME =#TABLE_NAME))
BEGIN
IF(LEN(#SQL)>0)
begin
SET #SQL =#SQL+' UNION ALL SELECT * FROM ['+#NAME+'].['+#TABLE_NAME+']'
end
ELSE
begin
SET #SQL ='SELECT * FROM ['+#NAME+'].['+#TABLE_NAME+']'
end
--PRINT #SQL
END
FETCH NEXT FROM CUR INTO #NAME
END
CLOSE CUR
DEALLOCATE CUR
PRINT #SQL
exec(#SQL)
Try this and remember Tables should have the same structure.
SELECT *
FROM schema1.tbl_user
UNION
SELECT *
FROM schema2.tbl_user
And for large number of schemas you can use the following stored procedure. This will generate the UNION query dynamically and you can add the conditions to filter out the schema and table names.
DECLARE #table_name NVARCHAR(100)
DECLARE #schema_name NVARCHAR(100)
DECLARE #gettable CURSOR
DECLARE #query NVARCHAR(100)
SET #query=''
SET #gettable = CURSOR FOR
SELECT name,
schema_name(schema_id)
FROM sys.tables
OPEN #gettable
FETCH NEXT
FROM #gettable INTO #table_name, #schema_name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #query = #query + 'SELECT * FROM ' + #schema_name + '.'+ #table_name + ' UNION ';
FETCH NEXT
FROM #gettable INTO #table_name, #schema_name
END
CLOSE #gettable
DEALLOCATE #gettable
print #query;

SQL - Add column and set value after IF NOT EXISTS

I'm having trouble with an Alter Table if a column doesn't exist.
This is my code:
DECLARE #appId INT
DECLARE #cursor CURSOR
IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME = 'MinMktIdeaParticipants' AND TABLE_NAME = 'mkIdeaCategories')
BEGIN
ALTER TABLE mkIdeaCategories
ADD MinMktIdeaParticipants int NOT NULL DEFAULT 1
END
IF EXISTS(SELECT Value FROM appConfiguration WHERE CodeId = 16 AND AppConfigurationTypeId = 3 AND ModuleId = 10)
BEGIN
SET #cursor = CURSOR FAST_FORWARD
FOR
SELECT ApplicationId FROM mkMarket
OPEN #cursor
FETCH NEXT FROM #cursor INTO #appId
WHILE (##Fetch_Status >= 0)
BEGIN
UPDATE
mkIdeaCategories
SET MinMktIdeaParticipants = (SELECT Value FROM appConfiguration
WHERE ApplicationId = #appId AND CodeId = 16 AND AppConfigurationTypeId = 3 AND ModuleId = 10)
WHERE IdeaCatId IN
(select distinct(theme.IdeaCatId) from dbo.mkIdeaCategories theme
inner join dbo.mkMarketIdeaCategories mic ON theme.IdeaCatId = mic.IdeaCatId
inner join mkMarket m on m.MarketId=mic.MarketId
WHERE m.ApplicationId = #appId)
FETCH NEXT FROM #cursor INTO #appId
END
CLOSE #cursor
DEALLOCATE #cursor
DELETE * FROM appConfiguration WHERE CodeId = 16 AND AppConfigurationTypeId = 3 AND ModuleId = 10
END
I don't think there are any errors. For some reason, the output error is
Msg 207, Level 16, State 1, Line 53
Invalid column name 'MinMktIdeaParticipants'.
I've already searched for similar questions, but couldn't find an answer that solved the problem.
When SQL Server processes a script, there are two phases. The first phase is compilation. The second is execution.
The error that you are getting is a compilation error. All the code is compiled, regardless of the if conditions. So, you are getting an error because the column doesn't exist. The column wouldn't be created until the execution phase.
One solution is to change the second part of the code to dynamic SQL, using exec (or better yet exec sp_executesql) to execute the code.
Gordon Linoff's solution will work. Another way to achieve what you want is to wrap your whole statement in a stored procedure.
this will fail:
select * from nonexisting_table
this will create a stored proc:
create procedure nonsense
as
begin
select * from nonexisting_table
end
BUT there are errors in your query:
SET #cursor = CURSOR FAST_FORWARD
To create a fast forward cursor in sql server you have to declare it.
Thats my favourite example from mssqltips.com:
DECLARE db_cursor CURSOR FAST_FORWARD FOR
SELECT name
FROM MASTER.dbo.sysdatabases
WHERE name NOT IN ('master','model','msdb','tempdb')
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #fileName = #path + #name + '_' + #fileDate + '.BAK'
BACKUP DATABASE #name TO DISK = #fileName
FETCH NEXT FROM db_cursor INTO #name
END
CLOSE db_cursor
DEALLOCATE db_cursor

Return a row from all tables and all databases?

How would be the SQL SELECT statement for returning a row from all data bases on the server, but just from a specific table and some of the columns of the table.
Or, in pseudo code, something like this:
for each(database)
{
return database.column.row;
}
This was not tested, but it should be enough to get you started.
DECLARE #name as NVARCHAR(128);
DECLARE #sql AS NVARCHAR(max);
DECLARE c_Cursor CURSOR FOR
SELECT databases.name
FROM sys.databases
WHERE databases.database_id > 4
ORDER BY databases.name;
OPEN c_Cursor;
FETCH NEXT FROM c_Cursor
INTO #name;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = N'SELECT table.* FROM ' + QUOTENAME(#name) + N'.dbo.table';
EXEC #sql
FETCH NEXT FROM c_Cursor
INTO #name;
END;
CLOSE c_Cursor;
DEALLOCATE c_Cursor;