Lorsque j'essaie de supprimer une base de données, j'obtiens l'erreur "Impossible de supprimer la base de données" nom_base "car elle est actuellement utilisée". Cependant, lorsque je lance sp_who2
, il n'y a certainement aucune session connectée à cette base de données. J'ai également défini la base de données sur single_user mode with rollback immediate
.
Pourquoi cela arrive-t-il?
Assurez-vous que vous n'avez pas de dépendances comme des instantanés de base de données sur la base de données que vous souhaitez supprimer. Cependant, le message d'erreur se présenterait autrement. Êtes-vous sûr qu'aucun processus masqué ne se connecte à votre base de données? Une bonne approche serait d'exécuter un script qui tue toutes les sessions et immédiatement après renommer la base de données sous un autre nom, puis supprimer la base de données.
créer un curseur basé sur cette sélection:
select d.name , convert (smallint, req_spid) As spid
from master.dbo.syslockinfo l,
master.dbo.spt_values v,
master.dbo.spt_values x,
master.dbo.spt_values u,
master.dbo.sysdatabases d
where l.rsc_type = v.number
and v.type = 'LR'
and l.req_status = x.number
and x.type = 'LS'
and l.req_mode + 1 = u.number
and u.type = 'L'
and l.rsc_dbid = d.dbid
and rsc_dbid = (select top 1 dbid from
master..sysdatabases
where name like 'my_db')
problème à l'intérieur du curseur:
SET @kill_process = 'KILL ' + @spid
EXEC master.dbo.sp_executesql @kill_process
PRINT 'killed spid : '+ @spid
une fois le curseur fermé et désalloué:
sp_dboption 'my_db', 'single user', 'TRUE'
go
sp_renamedb 'my_db', 'my_db_old'
go
DROP DATABASE MY_DB_OLD
Une session connectée à une autre base de données peut avoir une transaction ouverte qui affecte également votre base de données - sp_who2 n'affichera qu'une seule base de données. Cela pourrait également être quelque chose d'aussi simple que l'explorateur d'objets ou les détails de l'explorateur d'objets ouverts dans SSMS, qui ne montreraient encore qu'une seule base de données dans sp_who2.
Ne vous embêtez pas à essayer de trouver la session qui est responsable; tuez-les tous avec une seule instruction (et assurez-vous que ce n'est pas votre copie de SSMS qui est connectée, par exemple une autre fenêtre de requête, l'Explorateur d'objets, etc.):
USE master;
GO
ALTER DATABASE dbname SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
Maintenant, vous pourrez le supprimer et le faire en utilisant DDL, pas l'interface utilisateur:
DROP DATABASE dbname;
Quelle est votre base de données actuelle lorsque vous exécutez la commande DROP
? Essaye ça:
use master
go
drop database mydb
go
Assurez-vous également que vous êtes connecté en tant que sa
et non dbo
sur la base de données que vous souhaitez supprimer.
Que diriez-vous simplement de voir ce que fait SSMS lorsque vous utilisez l'interface utilisateur mais lui dites d'émettre un script pour l'action? Voici ce que fait SSMS lorsque vous cliquez avec le bouton droit sur la base de données et choisissez Supprimer, puis cochez la case pour fermer les connexions existantes:
EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = N'yourdbname'
GO
USE [master]
GO
ALTER DATABASE [yourdbname] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
USE [master]
GO
DROP DATABASE [yourdbname]
GO
J'ai fait face à cette situation à plusieurs reprises et voici ce que je fais:
Quand les méthodes évidentes ne fonctionnent pas ..... (comme dans votre situation):
Découvrez l'ID de la base de données dans sysdatabases.
Exécutez ensuite - sp_lock
qui affichera tous les verrous de l'instance ainsi que spid et dbid.
Tuez les spids avec la dbid que vous essayez de déconnecter ou de supprimer.
Bien que le processus soit un peu manuel, il peut être automatisé comme ci-dessous:
IF OBJECT_ID('tempdb.dbo.#temp', 'U') IS NOT NULL
DROP TABLE #temp;
create table #temp (spid int
, dbid int
,ObjId bigint
, IndId bigint
,Type varchar(5)
,resource varchar(max)
,Mode varchar(5)
,status varchar(10));
declare @dbid int
select @dbid =DB_ID(db_name())
insert into #temp
exec sp_lock
select * from #temp
where dbid = @dbid
J'ai trouvé une réponse très simple sur StackOverflow qui a fonctionné pour la première fois pour moi:
https://stackoverflow.com/a/7469167/261405
Voici le SQL de cette réponse:
DECLARE @DatabaseName nvarchar(50)
SET @DatabaseName = N'YOUR_DABASE_NAME'
DECLARE @SQL varchar(max)
SELECT @SQL = COALESCE(@SQL,'') + 'Kill ' + Convert(varchar, SPId) + ';'
FROM MASTER..SysProcesses
WHERE DBId = DB_ID(@DatabaseName) AND SPId <> @@SPId
--Use this to see results
SELECT @SQL
--Uncomment this to run it
--EXEC(@SQL)