September 29, 2017 at 12:55 pm
I have a SQL Server 2014 instance with quite a few databases on it. I want to change the compatibility level of the user databases. I'm trying to write a cursor to do this but I'm getting syntax errors with the variable inside the BEGIN/END. What am I doing wrong?
DECLARE @DBName VARCHAR(100)
DECLARE CompatCursor CURSOR FOR
SELECT NAME FROM master.dbo.sysdatabases
WHERE NAME NOT IN('master', 'tempdb', 'model', 'msdb')
OPEN CompatCursor
FETCH NEXT FROM CompatCursor INTO @DBName
WHILE @@FETCH_STATUS = 0
BEGIN
ALTER DATABASE @DBname SET SINGLE_USER
ALTER DATABASE @DBName SET Compatibility_level = 120
ALTER DATABASE @DBname SET MULTI_USER
FETCH NEXT FROM CompatCursor INTO @DBName
END
CLOSE CompatCursor
DEALLOCATE CompatCursor
September 29, 2017 at 2:33 pm
I have a slightly different approach for you to consider. Try running this - it generates all of the T-SQL for you, which you can cut, paste and execute:SELECT
d.name
, tsql = CONCAT(
'ALTER DATABASE ['
, d.name
, '] SET SINGLE_USER; ALTER DATABASE ['
, d.name
, '] SET Compatibility_level = 120; ALTER DATABASE ['
, d.name
, '] SET MULTI_USER;'
)
FROM sys.databases d
WHERE d.database_id > 4;
The absence of evidence is not evidence of absence.
Martin Rees
You can lead a horse to water, but a pencil must be lead.
Stan Laurel
October 1, 2017 at 5:56 pm
Just a bit of an FYI, I've not found it necessary to set the SINGLE USER mode in 2012 or 2016.
--Jeff Moden
Change is inevitable... Change for the better is not.
October 3, 2017 at 11:09 am
Your syntax error is because you're using a variable for the database name, you'd need some dynamic SQL to make it work.
If you still want to stick with a cursor, this should work for you. You could also put all the SET statements into the @sql variable at the same time and run it together rather than as separate executions.
DECLARE
@DBName VARCHAR(100)
,@SQL nvarchar(200)
DECLARE CompatCursor CURSOR FOR
SELECT NAME FROM master.dbo.sysdatabases
WHERE NAME NOT IN('master', 'tempdb', 'model', 'msdb')
OPEN CompatCursor
FETCH NEXT FROM CompatCursor INTO @DBName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = 'ALTER DATABASE [' + @DBName + '] ' + 'SET SINGLE_USER WITH ROLLBACK IMMEDIATE'
EXECUTE( @sql )
SET @sql = 'ALTER DATABASE [' + @DBName + '] ' + 'SET Compatibility_level = 120'
EXECUTE( @sql )
SET @sql = 'ALTER DATABASE [' + @DBName + '] ' + 'SET MULTI_USER'
EXECUTE( @sql )
FETCH NEXT FROM CompatCursor INTO @DBName
END
CLOSE CompatCursor
DEALLOCATE CompatCursor
October 3, 2017 at 3:38 pm
I've still not run into a problem with NOT setting the single user mode. Be VERY aware that will kill ALL connections but the current one and, if something goes wrong and the current window loses connection, one of the web servers will grab that single connection in a virtual heartbeat and you'll have one hell of a time getting back to the multi user mode.
And, yes... I know what the Microsoft recommendation is and why. If you decide to do it that way, you need to at least have a plan on how to get the single connection back if something goes haywire.
--Jeff Moden
Change is inevitable... Change for the better is not.
October 4, 2017 at 9:49 am
Phil, Thanks for that query. I've used that approach before on other things, I just didn't think of it this time.
October 4, 2017 at 9:57 am
SQL Pirate, That was the answer to my specific question, so thanks.
Jeff, I've frequently had to use the SET SINGLE_USER WITH ROLLBACK IMMEDIATE phrase but I'm not sure if that was on 2012 and above. Good warning about losing that one session while running the query.
Viewing 7 posts - 1 through 6 (of 6 total)
You must be logged in to reply to this topic. Login to reply