delete replication using script - replication

im using sql server 2012 and replication process in it. now the replication process is working correctly, but i want to delete this replication, i mean all the publications, subscriptions and articles through script. i went through this site http://support.microsoft.com/kb/324401 and tried the following script
:setvar PublisherDatabase "AdventureWorks2012"
:setvar SubscriberServer "HYDHTC0131320D\MSSQLSERVER2"
use [$(PublisherDatabase)]
--Drop all subscriptions
exec sp_dropsubscription
#publication = N'TestPubs',
#article = N'all',
--#subscriber = [$(SubscriberServer)]
#subscriber = N'all',
#destination_db = N'all'
--Drop publication
if exists (Select 1 From SysPublications where name = N'TestPubs')
EXEC sp_droppublication #publication = N'TestPubs'
EXEC sp_replicationdboption #dbname = [$(PublisherDatabase)], #optname = N'publish', #value = N'false'
--Drop subscriber entry
EXEC sp_dropsubscriber #subscriber = [$(SubscriberServer)]
--Drop distributor
EXEC sp_dropdistributor #no_checks = 1
after i execute the above script, im getting the following error.
Only one Log Reader Agent or log-related procedure (sp_repldone, sp_replcmds, and sp_replshowcmds) can connect to a database at a time. If you executed a log-related procedure, drop the connection over which the procedure was executed or execute sp_replflush over that connection before starting the Log Reader Agent or executing another log-related procedure.
Msg 18752, Level 16, State 1, Procedure sp_replcmds, Line 1
Only one Log Reader Agent or log-related procedure (sp_repldone, sp_replcmds, and sp_replshowcmds) can connect to a database at a time. If you executed a log-related procedure, drop the connection over which the procedure was executed or execute sp_replflush over that connection before starting the Log Reader Agent or executing another log-related procedure.
The Subscriber was dropped.
Msg 20015, Level 16, State 1, Procedure
sp_MSreplremoveuncdir, Line 83
Could not remove directory 'C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\ReplData\unc\HYDHTC0131320D_ADVENTUREWORKS2012_TESTPUBS\20120719152739\'. Check the security context of xp_cmdshell and close other processes that may be accessing the directory.
check this screenshot for more details
can anyone help me in solving these issues

It looks like you had some errors when dropping replication and have some orphaned subscription metadata at teh Subscriber. Orphaned metadata can be removed from the subscription database using sp_removedbreplication.
For future reference, you can remove all subscriptions, publications, and disable publishing and distribution following these steps:
Delete a Push Subscription
How to: Delete a Publication
Disabling Publishing and Distribution
Relevant bits of code from the links
a) To drop a push subscription on transactional replication
-- This batch is executed at the Publisher to remove
-- a pull or push subscription to a transactional publication.
DECLARE #publication AS sysname;
DECLARE #subscriber AS sysname;
SET #publication = N'AdvWorksProductTran';
SET #subscriber = $(SubServer);
USE [AdventureWorks2012]
EXEC sp_dropsubscription
#publication = #publication,
#article = N'all',
#subscriber = #subscriber;
GO
b) To drop a subscription on a merge replication
DECLARE #publication AS sysname;
DECLARE #subscriber AS sysname;
DECLARE #subscriptionDB AS sysname;
SET #publication = N'AdvWorksSalesOrdersMerge';
SET #subscriber = $(SubServer);
SET #subscriptionDB = N'AdventureWorks2012Replica';
USE [AdventureWorks2012]
EXEC sp_dropmergesubscription
#publication = #publication,
#subscriber = #subscriber,
#subscriber_db = #subscriptionDB;
GO
c) To drop a publication and set a source DB to stop being a publisher, on a transactional replication.
DECLARE #publicationDB AS sysname;
DECLARE #publication AS sysname;
SET #publicationDB = N'AdventureWorks2008R2';
SET #publication = N'AdvWorksProductTran';
-- Remove a transactional publication.
USE [AdventureWorks2008R2]
EXEC sp_droppublication #publication = #publication;
-- Remove replication objects from the database.
USE [master]
EXEC sp_replicationdboption
#dbname = #publicationDB,
#optname = N'publish',
#value = N'false';
GO
d) To drop a publication and set a source DB to stop being a publisher, on a merge replication.
DECLARE #publication AS sysname
DECLARE #publicationDB AS sysname
SET #publication = N'AdvWorksSalesOrdersMerge'
SET #publicationDB = N'AdventureWorks2008R2'
-- Remove the merge publication.
USE [AdventureWorks2008R2]
EXEC sp_dropmergepublication #publication = #publication;
-- Remove replication objects from the database.
USE master
EXEC sp_replicationdboption
#dbname = #publicationDB,
#optname = N'merge publish',
#value = N'false'
GO

My workaround is to do sp_droppublication in a transaction.
-- local variables
declare
#return_code int -- return code of sp
,#dependent_publ sysname -- publication dependent on replicated RDZ tables
declare a cursor for
select distinct p.name from syspublications p
inner join sysarticles s on p.pubid = s.pubid
inner join adm_replicated_rdz_tables r on r.table_name = s.name
if exists
(select * from sys.objects
where object_id = object_id('[dbo].[sysarticles]') and type in ('U'))
begin
open a; fetch next from a into #dependent_publ; while ##fetch_status = 0
begin
begin transaction
print #dependent_publ
execute sp_droppublication #dependent_publ;
commit
fetch next from a into #dependent_publ;
end; close a; deallocate a;
end

Related

SQL Server - DDL Trigger to modify Table after its creation

I have a 3rd party program which exports data to SQL Server.
However, such program can not insert, but drops and recreates each tables with the data each time it is processed.
There is a specific schema for that.
I need to run modifications on such table on SQL each time it is re-created.
I have been trying using a DDL trigger on Create, which just writes the name of the table to a LOG if it's in the target schema:
CREATE TRIGGER [tCREATE_TABLE] ON DATABASE
FOR CREATE_TABLE
AS
DECLARE #data XML;
DECLARE #schema sysname;
DECLARE #schema_s nvarchar(128);
DECLARE #object sysname;
DECLARE #object_s nvarchar(128);
DECLARE #eventType sysname;
SET #data = EVENTDATA();
SET #eventType = #data.value('(/EVENT_INSTANCE/EventType)[1]',
'sysname');
SET #schema = #data.value('(/EVENT_INSTANCE/SchemaName)[1]','sysname');
SET #schema_s = CAST(#schema as nvarchar(128));
SET #object = #data.value('(/EVENT_INSTANCE/ObjectName)[1]','sysname');
SET #object_s = CAST(#object as nvarchar(128));
-- COMMIT should unlock the table...??
COMMIT
IF #schema_s = 'TARGET_SCHEMA'
INSERT INTO [TARGET_SCHEMA].[UpdateLOG](TabName,LOAD_UPDATEDATE,LOAD_USER)
VALUES (#object_s,GETDATE(),CURRENT_USER)
-- this is the procedure that modifies the target table
EXEC [ProcessTableProcedure]
#targettab = #object_s
GO
This works for writing to a log, but as soon as I add call the processing procedure it returns an error.
At the end of the trigger, the modifying procedure won't find the table - since the transaction is not committed yet.
I have put a COMMIT before that, but then nothing happens (procedure is not run).
I assume the trigger ends after the COMMIT...?
Any help?

How to pass a table type to a stored procedure in a job?

I need to create a stored procedure that's called within a temporary job, so I'm doing:
CREATE PROCEDURE create_test_job
#criteria Criteria READONLY
AS
BEGIN
DECLARE #jobName nvarchar(max);
SET #jobName = 'test';
--Get database name
DECLARE #dbName sysname;
SELECT #dbName = DB_NAME();
--Create job
EXEC msdb.dbo.sp_add_job #job_name = #jobName;
--Create step
EXEC msdb.dbo.sp_add_jobstep
#job_name = #jobName,
#step_name = 'Step 1',
#subsystem = N'TSQL',
#database_name = #dbName,
#command = N'EXEC my_actual_sp ' + #criteria;
----TODO Schedule the job at a specified date and time
----TODO Add the job to the SQL Server server
EXEC msdb.dbo.sp_delete_job #job_name = #jobName;
END
GO
And obviously #command is wrong. How can I pass the table type to my sp?
You'll have to spill the contents into a real table, and re-read that inside your job.
Something like:
INSERT INTO PendingCriteria (/* Columns */)
SELECT /* Columns */ FROm #Criteria
...
#command = N'DECLARE #C Criteria
INSERT INTO #C (/* Columns */) SELECT /* Columns */ FROM PendingCriteria
EXEC my_actual_sp #C';
I'd then probably do the cleanup of the permanent table as a separate job step.
The problem is that jobs represent something to be done in the (for a computer) far future. Table-variables represent an object that exists solely in the here-and-now. They're also local to the session - when the job runs in the future it will be running each step in a new session.

SELECT specific columns from EXEC stored procedure

I am having an issue trying to SELECT specific columns from an EXEC statement on a stored procedure. I am trying to find the COUNT(*) that the stored procedure returns which I am successfully doing with :
INSERT INTO #temp
EXEC dbo.my_sp
SET #count = (SELECT COUNT(*) FROM #temp)
DELETE FROM #temp
However, this only works if the columns returned match specifically with the table columns and since I am trying to find the count of many different stored procedures (each of which return different columns), I cannot use this method without creating a new table for each stored procedure.
Is there a way I can SELECT specific columns from the EXEC dbo.my_sp?
Create a loopback linked server to the local instance, making sure that data access is enabled. Let's say you have a local named instance called YourServer\SQL2008:
USE [master];
GO
EXEC sp_addlinkedserver
#server = N'LoopbackLocal',
#srvproduct = N'',
#provider = N'SQLNCLI',
#datasrc = N'.\SQL2008',
#catalog = N'tempdb';
GO
EXEC sp_serveroption
#server = N'LoopbackLocal',
#optname = N'collation compatible',
#optvalue = N'true';
GO
EXEC sp_serveroption
#server = N'LoopbackLocal',
#optname = N'data access',
#optvalue = N'true';
GO
EXEC sp_addlinkedsrvlogin
#rmtsrvname = N'LoopbackLocal',
#locallogin = NULL ,
#useself = N'True';
GO
-- you may need to configure other security here
Then you can use OPENQUERY to run a stored procedure as if it were an ad hoc query.
SELECT COUNT(*)
FROM OPENQUERY
(
LoopbackLocal,
'EXEC dbo.my_sp'
) AS y;
Now, if dbo.my_sp dumps information into a #temp table first, you're going to have issues, since it is no longer a block of code that OPENQUERY can process. For example, if you try to execute sp_who2 this way, at least in SQL Server 2012, you will get an error from sp_describe_first_result_set which OPENQUERY has been altered to use (so maybe this works for you now, I don't have 2008 to test, but it will be an issue someday):
Msg 11526, Level 16, State 1, Procedure sp_describe_first_result_set, Line 1
The metadata could not be determined because ... uses a temp table.
If you're going to be doing this a lot, however, why not make specialized stored procedures (or add options to these ones) such that only a count is returned?
Would ##ROWCOUNT work for you?
if OBJECT_ID('SomeProc') is null
exec ('create procedure dbo.SomeProc as select 1 as SomeValue union all select 2 as SomeValue;')
exec dbo.SomeProc
Select ##ROWCOUNT as RowsAffected
http://technet.microsoft.com/en-us/library/ms187316(v=sql.105).aspx

SQL Server Kill Command

I have an SQL script which backs up a database and then restores it over another database. the problem I'm having is that the database being overwritten is being locked open by a user so the job fails. I can manually kill the attached user and it runs fine but I need this process to run automatically every night. Is there a kill command which I can time to execute every night? or is there something in the restore options to do the same thing?
Any thoughts?
Thanks
KILL isn't always effective if the client reconnects
I'd consider taking the database offline (or dbo only) then restoring. Thus will prevent further reconnects.
ALTER DATABASE TargetDB SET OFFLINE WITH ROLLBACK IMMEDIATE
or
ALTER DATABASE TargetDB SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE
agree with #gbn you can use following code to get database restore success also
USE master
GO
ALTER DATABASE YourDatabaseName SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
ALTER DATABASE YourDatabaseName SET OFFLINE WITH ROLLBACK IMMEDIATE
GO
however you can use following script to kill connections to selected database.
-- Create the sql to kill the active database connections
DECLARE #execSql VARCHAR(4000),
#databaseName VARCHAR(100)
-- Set the database name for which to kill the connections
SET #databaseName = '[yourdatabase]'
SET #execSql = ''
SELECT #execSql = #execSql + 'kill ' + CONVERT(CHAR(10), spid) + ' '
FROM master.dbo.sysprocesses
WHERE DB_NAME(dbid) = #databaseName
AND DBID <> 0
AND spid <> ##spid
EXEC ( #execSql
)
DECLARE #pid AS INTEGER
DECLARE mycursor CURSOR FOR
select spid
from sys.sysprocesses
WHERE dbid = DB_ID('yourdatabasename')
OPEN mycursor
FETCH NEXT FROM mycursor INTO #pid
WHILE ##FETCH_STATUS = 0
BEGIN
EXECUTE ('KILL '+#pid)
FETCH NEXT FROM mycursor INTO #pid
END
CLOSE mycursor
DEALLOCATE mycursor
Select 'Kill '+ CAST(p.spid AS VARCHAR)KillCommand into #temp
from master.dbo.sysprocesses p (nolock)
join master..sysdatabases d (nolock) on p.dbid = d.dbid
Where d.[name] = 'your db name'
Declare #query nvarchar(max)
--Select * from #temp
Select #query =STUFF((
select ' ' + KillCommand from #temp
FOR XML PATH('')),1,1,'')
Execute sp_executesql #query
Drop table #temp
Use the ‘master’ database and run this query, it will kill all the active connections from your database.

What is the SQL command to forcibly close all other connections to the a database

What is the SQL command to forcibly close all other connections to the a database.
This is for SQL Server 2008
One way using ROLLBACK IMMEDIATE
ALTER DATABASE foo SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
You can use KILL but you want to prevent re-connections too.
Use the Kill statement to close a single connection:
Terminates a user process that is
based on the session ID (SPID in SQL
Server 2000 and earlier)
Without further comment, here's a stored procedure we've used off and on over the years, to close all connections, using kill. I'm sure there's a better/non-cursor way to do this.
CREATE PROCEDURE kill_database_users #arg_dbname sysname
AS
declare #a_spid smallint
declare #msg varchar(255)
declare #a_dbid int
select
#a_dbid = sdb.dbid
from master..sysdatabases sdb
where sdb.name = #arg_dbname
declare db_users insensitive cursor for
select
sp.spid
from master..sysprocesses sp
where sp.dbid = #a_dbid
open db_users
fetch next from db_users into #a_spid
while ##fetch_status = 0
begin
select #msg = 'kill '+convert(char(5),#a_spid)
print #msg
execute (#msg)
fetch next from db_users into #a_spid
end
close db_users
deallocate db_users