EXEC sp_testlinkedserver over multiple Linked Servers - sql

I'm trying to get error messages over all my Linked Servers.
So I've three Linked Servers:
IT_DATA
193.0.1
Monitoring_Data
I know that executing the following query I will get the info that I need to one Linked Server:
BEGIN TRY
EXEC sp_testlinkedserver N'193.0.1';
EXEC sp_executesql N'SELECT * FROM OPENQUERY([193.0.1], ''SELECT 1 AS c;'');';
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH;
PRINT 'We got past the Catch block!';
But I'm trying to create a loop to exec the SP to all of my Linked Servers:
DECLARE #Linked_Server varchar(50)
SET #Linked_Server = '193.0.1'
BEGIN TRY
EXEC sp_testlinkedserver N'193.0.1';
EXEC sp_executesql N'SELECT * FROM OPENQUERY([193.0.1], ''SELECT 1 AS c;'');';
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH;
PRINT 'We got past the Catch block!';
But I don't know how can I create a loop to get the information of all the Linked Servers into one table.
Anyone have an closer example?
Thanks!

I don't like using cursors but in this case... Try this:
create table dbo.LinkedServer (
LSName nvarchar(128)
, ErrorNumber int
, ErrorMessage nvarchar(4000)
);
DECLARE #Linked_Server nvarchar(128)
, #SQLString nvarchar(max);
declare crsLinkedServers cursor
for
select
s.name
from sys.servers s
where s.is_linked = 1;
open crsLinkedServers;
fetch next from crsLinkedServers
into #Linked_Server;
while ##fetch_status = 0
begin
BEGIN try
set #SQLString = N'SELECT * FROM OPENQUERY([' + #Linked_Server + '], ''SELECT 1 AS c;'');'
EXEC sp_testlinkedserver #Linked_Server;
EXEC sp_executesql #SQLString;
END TRY
BEGIN catch
insert into dbo.LinkedServer (LSName, ErrorNumber, ErrorMessage)
SELECT #Linked_Server, error_number(), error_message();
END CATCH;
fetch next from crsLinkedServers
into #Linked_Server;
end
close crsLinkedServers;
deallocate crsLinkedServers;
select
*
from dbo.LinkedServer;
drop table dbo.LinkedServer;

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.

How to check whether all transactions in the loop(cursors) are success or not in sql?

I am using cursor to delete set of tables. I need to set flag to identify whether all transactions are success or not. Can you please give me some sample queries?
DEclare #intErrorCode int;
DECLARE #TblName NVARCHAR(MAX);
DECLARE TBL_Cursor CURSOR
FOR ( select name from sysobjects where name like 'tbl_flat%');
OPEN TBL_Cursor;
FETCH NEXT FROM TBL_Cursor INTO #TblName
WHILE (##FETCH_STATUS <> -1)
BEGIN
IF LEN(#TblName) >0
BEGIN
DECLARE #strsql nvarchar(max)
BEGIN
something here
BEGIN TRAN
EXEC sp_executesql #strsql
COMMIT TRAN
SELECT #intErrorCode = ##ERROR
IF (#intErrorCode <> 0) GOTO PROBLEM
END
END
FETCH NEXT FROM TBL_Cursor INTO #TblName
END
CLOSE TBL_Cursor
DEALLOCATE TBL_Cursor
PROBLEM:
IF (#intErrorCode <> 0) BEGIN
PRINT 'Unexpected error occurred!'
END
BEGIN TRY
BEGIN TRANSACTION
--your code
EXEC sp_executesql #strsql
COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN --RollBack in case of Error
-- you can Raise ERROR with RAISEERROR() Statement including the details of the exception
RAISERROR(ERROR_MESSAGE(), ERROR_SEVERITY(), 1)
END CATCH

create a try and catch inside loop

I want to loop though the "RPT_ID = 245 " from 1 to 245 and inside the try and catch the invalid query statements so that the invalid queries will be caught.
The query column is a dynamic sql statement created for reports.
alter PROCEDURE usp_ExampleProc
AS
declare
#vsql2 as nvarchar(max)
,#vquery2 as nvarchar(max)
,#value as nvarchar(max)
,#value2 as nvarchar(max)
,#Q1 as nvarchar(max)
,#RP_NUM as nvarchar(max)
,#count as int
select #count = count(*) from saved_reports
while #count > 0
begin
select #q1 = query,#RP_NUM =RPT_ID from SAVED_REPORTS WHERE RPT_ID = #count
exec sys.sp_executesql #q1
BEGIN TRY
EXECUTE usp_ExampleProc;
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber
,ERROR_MESSAGE() AS ErrorMessage;
END CATCH
set #count = #count - 1
end
use
EXECUTE usp_GetErrorInfo;
in your catch statement.
see http://technet.microsoft.com/en-us/library/ms175976.aspx

sp_OAMethod 'DeleteFile' Method not working in SQL Server 2008 R2

I have an sql stored procedure that I use to delete files from the windows file system using the sp_OAMethod. This used to work fine when we were using sql server 2005, however, it does not work at all now when using sql server 2008 R2. I have read that you can use SQLDMO/SQLCLR however, I cannot find any decent information regarding these methods. My previous code is below:
-- declare variables
declare #ObjectID nvarchar(10),
#ObjectType nvarchar(255),
#BackupName nvarchar(255),
#BackupLocation nvarchar(255),
#ExpiryDate datetime,
#DeletedStatus bit,
#SQL nvarchar(4000),
#SQL1 nvarchar(4000),
#SQL2 nvarchar(4000),
#Result int,
#FSO_Token int,
#FileLocation nvarchar(4000)
-- declare cursor for table backups
declare backupexpired_cursor cursor for
select dbo.tbl_BackupObjects.ObjectID, dbo.tbl_BackupObjects.ObjectType, dbo.tbl_BackupObjects.BackupName,
dbo.tbl_BackupObjects.BackupLocation, dbo.tbl_BackupObjects.ExpiryDate, dbo.tbl_BackupObjects.Deleted
from dbo.tbl_BackupObjects
where dbo.tbl_BackupObjects.Deleted <> 1
-- open cursor
open backupexpired_cursor
-- fetch the next record from the cursor
fetch next from backupexpired_cursor into #ObjectID, #ObjectType, #BackupName, #BackupLocation, #ExpiryDate, #DeletedStatus
while (##FETCH_STATUS <> -1)
begin
if (##FETCH_STATUS <> -2)
begin
if (#ExpiryDate < GetDate())
begin
if (#ObjectType = 'Table')
begin
begin try
begin transaction
-- Only done if the object type is a table object
-- Remove old backup
select #SQL = 'drop table dbo.' + quotename(#BackupName)
exec sp_executesql #SQL
-- update the deleted status and the date deleted of the deleted object
select #SQL1 = 'update tbl_BackupObjects
set Deleted = 1,
DeletedDate = GetDate()
where ObjectID = ''' + #ObjectID + ''''
exec sp_executesql #SQL1
commit transaction
end try
begin catch
rollback transaction
select #SQL1 = 'update tbl_BackupObjects
set Deleted = 0,
DeletedDate = NULL
where ObjectID = ''' + #ObjectID + ''''
exec sp_executesql #SQL1
end catch
end
else
begin
begin try
begin transaction
-- Only done if the object(view, stored procedure, and/or function is saved
-- in a file located on the windows file system.
-- Create File Location
set #FileLocation = 'G:\Backup Registry Script Files\' + #BackupLocation + '\' + #BackupName + ''
-- Create a token of the object
EXEC #Result = sp_OACreate 'Scripting.FileSystemObject', #FSO_Token OUTPUT
-- Call the deletefile method using the #FileLocation parameter and the token created above:
-- - The object token created by sp_OACreate
-- - The method name
-- - The method's return value
-- - Parameters that will be used by the object method
EXEC #Result = sp_OAMethod #FSO_Token, 'DeleteFile', NULL, #FileLocation
-- Execute ole method
EXEC #Result = sp_OADestroy #FSO_Token
-- update the deleted status and the date deleted of the deleted object
select #SQL1 = 'update tbl_BackupObjects
set Deleted = 1,
DeletedDate = GetDate()
where ObjectID = ''' + #ObjectID + ''''
exec sp_executesql #SQL1
commit transaction
end try
begin catch
rollback transaction
select #SQL1 = 'update tbl_BackupObjects
set Deleted = 0,
DeletedDate = GetDate()
where ObjectID = ''' + #ObjectID + ''''
exec sp_executesql #SQL1
end catch
end
end
end
-- fetch the next record from the cursor
fetch next from backupexpired_cursor into #ObjectID, #ObjectType, #BackupName, #BackupLocation, #ExpiryDate, #DeletedStatus
end
-- set the Last and Next Removal Dates
select #SQL2 = 'update tbl_BackupRemovalDate
set LastRemovalDate = GetDate(),
NextRemovalDate = GetDate() + 7'
exec sp_executesql #SQL2
-- close cursor
close backupexpired_cursor
deallocate backupexpired_cursor
I have seen that SQLDMO is quite similar to what I have, however I cannot find any information on how to delete a file system file using this method. Can anyone help?
Do you have Enable Ole Automation Procedures feature ?
try this
EXEC sp_configure 'show advanced options', 1
RECONFIGURE
EXEC sp_configure 'Ole Automation Procedures', 1
RECONFIGURE

EXEC within the TRY...CATCH block

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