set database to multi_user through management studio - sql-server

I have had to set my database to single_user mode to allow for a dbcc checkdb repair and now I am unable to get my database back to multi_user. I have tried the following command in a query window against the master database but it hasn't worked as suggested by another Stack overflow post:
USE [master];
GO
ALTER DATABASE mydb SET MULTI_USER WITH ROLLBACK IMMEDIATE;
GO
I get the following error:
Msg 5064, Level 16, State 1, Line 2 Changes to the state or options of
database 'mydb' cannot be made at this time. The database is in
single-user mode, and a user is currently connected to it.
Msg 5069,
Level 16, State 1, Line 2 ALTER DATABASE statement failed.
If I right click on the database and try selecting properties then it errors saying that it is already in use.
Any help would be greatly appreciated.

Try killing the existing connection and setting MULTI_USER in the same batch:
USE master;
GO
DECLARE #sql nvarchar(MAX);
SELECT #sql = STRING_AGG(N'KILL ' + CAST(session_id as nvarchar(5)), ';')
FROM sys.dm_exec_sessions
WHERE database_id = DB_ID(N'mydb');
SET #sql = #sql + N';ALTER DATABASE mydb SET MULTI_USER;';
--PRINT #sql;
EXEC sp_executesql #sql;
GO

To get the session that was tied to the database I ran:
SELECT request_session_id
FROM sys.dm_tran_locks
WHERE resource_database_id = DB_ID('mydb')
This yielded a processid of 55
I then ran:
kill 55
go
And I was the able to use the alter multi_user line that was previously not working

The most likely reason why you're getting this error is that you still have the original session open that you used to set the database to single user. If you execute the above SQL in the same session that you set the database to single user in, it will work.

First try selecting the master database and run the alter command.
If it does not work, There exists some open connections to database and you can check and kill the processes
use master
GO
select
d.name,
d.dbid,
spid,
login_time,
nt_domain,
nt_username,
loginame
from sysprocesses p
inner join sysdatabases d
on p.dbid = d.dbid
where d.name = 'dbname'
GO
kill 52 -- kill the number in spid field
GO
exec sp_dboption 'dbname', 'single user', 'FALSE'
GO

Related

SQL Server returns error with sp_trace_generateevent

I get an error from one of my databases when trying to execute this one
create or alter procedure [dbo].[test_sp]
with execute as owner
as
SELECT SUSER_SNAME()+ ' '+ USER_NAME();
begin
exec master..sp_trace_generateevent #eventid = 82 ,
#userinfo=N'test'
end
GO
exec [dbo].[test_sp]
Error:
Msg 8189, Level 14, State 10, Procedure master..sp_trace_generateevent, Line 1 [Batch Start Line 9]
You do not have permission to run 'SP_TRACE_GENERATEEVENT'.
Granted ALTER TRACE to my user (which returns in SUSER_SNAME()), but it wasn't help
The same script on the second database (same server) works without errors.
What else can it be?
You're trying to run this with EXECUTE AS OWNER, and the owner is a database-level principal and you can't operate outside the current database while impersonating a database-level principal. Switch to EXECUTE AS CALLER (the default) to have the caller's identity used to run the proc in master. eg
create or alter procedure [dbo].[test_sp]
with execute as caller
as
SELECT SUSER_SNAME()+ ' '+ USER_NAME();
begin
exec master..sp_trace_generateevent #eventid = 82, #userinfo = N'test'
end
GO
exec [dbo].[test_sp]
This can be made to work with owner-impersonation by marking the database as TRUSTWORTHY. See: Extending Database Impersonation by Using EXECUTE AS and Guidelines for using the TRUSTWORTHY database setting in SQL Server

ALTER DATABASE [...] SET SINGLE_USER WITH NO_WAIT waits 20 seconds

On SQL Server 2012, when I am issuing a statement
ALTER DATABASE [...] SET SINGLE_USER WITH NO_WAIT
and someone else is using the database, I have to wait for approximately 20 seconds until the request fails, despite the NO_WAIT termination clause.
Is it possible to tell SQL Server to let the "ALTER DATABASE" request fail immediately? Preferrably also for older versions of SQL Server? (although it seems that "ALTER DATABASE [...] SET" is not supported in SQL Server 2005 and earlier).
Give this a try. It checks for active connections to the database before trying to put it into SINGLE_USER mode.
use master
GO
DECLARE #DBName SYSNAME = N'YourDbName'
IF NOT EXISTS (
SELECT sd.Name, sp.*
FROM sys.sysprocesses sp
JOIN sys.sysdatabases sd
ON sd.dbid = sp.dbid
WHERE sd.Name = #DBName
AND sp.spid <> ##SPID
)
BEGIN
ALTER DATABASE [...]
SET SINGLE_USER WITH NO_WAIT
END

What are the user permissions needed to enable snapshot isolation in a DB?

I have a user who has db_datareader, db_datawriter permissions on a DB.
I want to set the isolation levels to the DB to which the user has access to.
What permissions will my user need to be able to set these.
DB used: SQL SERVER 2008
This is not setting an isolation level:
ALTER DATABASE dbname SET ALLOW_SNAPSHOT_ISOLATION ON;
That is altering the database. For that you need to provide them with ALTER rights on the database:
GRANT ALTER ON DATABASE::dbname TO username;
Otherwise you get this error:
Msg 5011, Level 14, State 9, Line 1
User does not have permission to alter database 'dbname', the database does not exist, or the database is not in a state that allows access checks.
Msg 5069, Level 16, State 1, Line 1
ALTER DATABASE statement failed.
Now, ALTER is all or nothing - you can't use it to allow them to change the allow snapshot setting but not other settings like forced parameterization, compatibility level, etc. You can do this much more granularly, though; perhaps you could create a stored procedure that does something like this:
CREATE PROCEDURE dbo.SetIsolationLevel
WITH EXECUTE AS OWNER
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX) = N'ALTER DATABASE '
+ QUOTENAME(DB_NAME())
+ ' SET ALLOW_SNAPSHOT_ISOLATION ON;';
EXEC sp_executesql #sql;
END
GO
Now you just have to give the user EXEC permissions on that procedure, which your user can now call (instead of the ALTER DATABASE command explicitly and instead of giving them full ALTER DATABASE privileges):
GRANT EXEC ON dbo.SetIsolationLevel TO username;
GO
You can simulate them calling this stored procedure by logging in as them, or using the EXECUTE AS feature directly:
EXECUTE AS USER = 'username';
GO
EXEC dbo.SetIsolationLevel;
GO
REVERT;
GO
Another idea is to simply set the model database to have this setting, than any new databases that get created for your users will automatically inherit it, then you don't have to worry about making them turn it on.
ALTER DATABASE model SET ALLOW_SNAPSHOT_ISOLATION ON;
GO
CREATE DATABASE splunge;
GO
SELECT snapshot_isolation_state_desc FROM sys.databases WHERE name = N'splunge';
Result:
ON

Dropping SQL Server database: handling concurrent connections

During my integration tests, I try to drop database using:
USE master
ALTER DATABASE TestXyz SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DROP DATABASE TestXyz
However, quite often (given the number of tests) one of the application background processes manages to get between SET SINGLE_USER and DROP DATABASE, which makes it single user of the database and breaks the DROP.
I can not use RESTRICTED_USER, as the application currently has db_owner permission (due to a large amount of legacy code, some of which requires it, so it will not be changed just for the tests).
I can not use OFFLINE as it does not delete database files from the disk.
How would you solve this problem?
OK plan b... iterate a drop of connections and rename the DB to get it away from the applications domain. Then drop it. To handle iterating through connections a try catch on the rename will hopefully allow it to run until it is able to drop the connection. Example code below creates a DB TestDB; renames it to testdb2 in the while loop before dropping it after the loop has succeeded.
-- Setup a scratch Db for testing
create database testdb
go
use testdb
while exists (select name from sys.databases where name = 'testdb')
Begin
DECLARE #DbName nvarchar(50) SET #DbName = N'testdb'
DECLARE #EXECSQL varchar(max) SET #EXECSQL = ''
SELECT #EXECSQL = #EXECSQL + 'Kill ' + Convert(varchar, SPId) + ';'
FROM MASTER..SysProcesses
WHERE DBId = DB_ID(#DbName) AND SPId <> ##SPId
EXEC(#EXECSQL)
Begin try
EXEC sp_renamedb 'testdb', 'testdb2'
end try
Begin Catch
print 'failed to rename'
End Catch
end
drop database testdb2
Try this once:
Stop application services and run your query.
Stop application services and restart SQL Server Services and then run your query.
I have finally solved it using the following approach:
ALTER LOGIN MyAppUser DISABLE
ALTER DATABASE TestXyz SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DROP DATABASE TestXyz
ALTER LOGIN MyAppUser ENABLE
Since I can use different login for test database management process, this allows me to block application from accessing the DB. (The reason for SINGLE_USER here is just to kick already connected users. I haven't checked if ALTER LOGIN already does that, but I assume it does not).
Alternative option is to delete MyAppUser from the database before dropping it, however I thought about it only now and do not have code for it.

Shrinklog all user databases in SQL2008

Hi I am using this script in the process of weekly maintenance, suggest best approach/scripts to do shrinklog. Currently am getting an error with the below script
declare #s nvarchar(4000)
set #s= '
if ''?'' not in (''tempdb'',''master'',''model'',''msdb'')
begin
use [?]
Alter database [?] SET Recovery simple
end '
exec sp_msforeachdb #s
set #s= '
if ''?'' not in (''tempdb'',''master'',''model'',''msdb'')
begin
use [?]
Declare #LogFileLogicalName sysname
select #LogFileLogicalName=Name from sys.database_files where Type=1
DBCC Shrinkfile(#LogFileLogicalName,1)
end'
exec sp_msforeachdb #s
Error Description:
ShrinkLog Execute SQL Task Description: Executing the query "declare #s nvarchar(4000) set #s= ' ..." failed with the following error: "Option 'RECOVERY' cannot be set in database 'tempdb'. Cannot shrink log file 2 (DBServices_Log) because total number of logical log files cannot be fewer than 2. DBCC execution completed. If DBCC printed error messages, contact your system administrator.
note: I am avoiding tempdb(all System db) in my script, but error message shows tempdb?
This is probably the worst maintenance script I've seen in the past year. A maintenance script that every week breaks the log chain and makes the database unrecoverable?? OMG. Not to mention that the simple premise of shrinking the log on a maintenance task is wrong. If the database log has grown to a certain size, than that size is needed. Schedule log backups more frequently to prevent this, but don't schedule log shrink operations.
You can avoid the 5058 error by using an exec statement to alter the database recovery model. The following script will set each user database to a simple recovery model. (It uses Jimmy's answer to detect system databases.)
exec sp_msforeachdb 'if exists (select name from sys.databases d where case when d.name in (''master'',''model'',''msdb'',''tempdb'') then 1 else d.is_distributor end = 0
and name = ''?'' and recovery_model_desc != ''SIMPLE'')
begin
declare #previousRecoveryModel varchar(100) = (select recovery_model_desc from sys.databases where name = ''?'');
print ''Changing recovery model for ? from '' + #previousRecoveryModel + '' to SIMPLE.'';
use master;
-- Using exec avoids a compile-time 5058 error about tempdb, which is a branch that will never be executed in this code.
exec (''alter database [?] set recovery simple'');
end';
Then you won't get the compile-time error about tempdb because the exec statement will compile its statement with the database name variable already substituted.

Resources