I am trying to change the recovery model of the current database.
This is what I have:
DECLARE #dbName VARCHAR(50)
SELECT #dbName = DB_NAME()
ALTER DATABASE #dbName SET RECOVERY SIMPLE WITH NO_WAIT
#dbName gives me:
Incorrect syntax near '#dbName'.
I tried:
ALTER DATABASE database_id SET RECOVERY SIMPLE WITH NO_WAIT
database_id gives me:
Msg 5011, Level 14, State 5, Line 3 User does not have permission to
alter database 'database_id', the database does not exist, or the
database is not in a state that allows access checks.
How should I execute this on the current database?
DECLARE #sql NVARCHAR(MAX) = N'ALTER DATABASE '
+ QUOTENAME(DB_NAME())
+ ' SET RECOVERY SIMPLE WITH NO_WAIT;';
EXEC sp_executesql #sql;
Related
This question already has answers here:
How to use a variable for the database name in T-SQL?
(4 answers)
Closed 2 years ago.
I have a problem with assigning a database name to a variable. When I do this, I get a message that there is no such database.
What am I doing wrong that this script doesn't work?
DECLARE #db_name varchar(10)
SET #db_name = 'xxx'
ALTER TABLE [#db_name].[dbo].[Table_Name]
DROP CONSTRAINT [Constraint_Name]
GO
ALTER TABLE [#db_name].[dbo].[Table_Name] WITH CHECK
ADD CONSTRAINT [Constraint_Name] CHECK (QUERY)
GO
ALTER TABLE [#db_name].[dbo].[Table_Name] CHECK CONSTRAINT [Constraint_Name]
GO
I'm getting this error message:
Msg 2702, Level 16, State 2, Line 5
Database '#db_name' does not exist.
Msg 2702, Level 16, State 2, Line 8
Database '#db_name' does not exist.
Msg 2702, Level 16, State 2, Line 11
Database '#db_name' does not exist.
let's say for example that you have a table created like this:
create table xxx(id int
CONSTRAINT AK_TransactionID UNIQUE(id))
Then you will need to cerate two variables(one for the object name and one for the query to be executed...):
DECLARE #db_name varchar(10) ;
DECLARE #query nvarchar(500) ;
Set them to the values you need:
SET #db_name = 'xxx';
set #query = 'ALTER TABLE ['+ #db_name +' ] DROP CONSTRAINT [AK_TransactionID]';
And then execute the query:
EXEC sp_executesql #query;
Here is a demo
A query - meaning all text until each GO command - is compiled before it is run.
Database names inside queries have to be be known at compile time, because the database + any table or column you specify are inspected by the query compiler to see if they are valid.
This means that Database names + Table names + Column names all cannot come from #-variables, because at compile time variables don't yet exist and have no value.
The fix is to use dynamic SQL:
DECLARE #db_name varchar(10) = 'xxx'
DECLARE #sql varchar(1000) = 'ALTER TABLE [' + #db_name + '].[dbo].[Table_Name] DROP CONSTRAINT [Constraint_Name]'
EXEC (#sql)
Unfortunately in SQL Server, you cannot pass schema, database, table or column names as a parameter - if you want to do this, you must use dynamic SQL. You could do the below to achieve this:
DECLARE #db_name VARCHAR(MAX)
DECLARE #SQL VARCHAR(MAX)
SET #db_name = [xxx]
SET #SQL = 'ALTER TABLE' + #db_name+ '.[dbo].[Table_Name] DROP CONSTRAINT [Constraint_Name]'
EXEC (#SQL)
SET #SQL = 'ALTER TABLE' + #db_name + '.[dbo].[Table_Name] WITH CHECK ADD CONSTRAINT [Constraint_Name] CHECK (QUERY)'
EXEC (#SQL)
SET #SQL = 'ALTER TABLE' + #db_name + '.[dbo].[Table_Name] CHECK CONSTRAINT [Constraint_Name]'
EXEC (#SQL)
I posted yesterday because we have a database that was basically used for application purposes but it was using "master" - bad indeed. We created a new database called school that is now being used (same structure as how master was minus a table renamed correctly). I was trying to restore a .bak file from the old db (master from sql 2008) to the new school db (school in sql 2016).
Problem is, running the script gave me a bunch of lines saying it's updating, then the restore terminated abnormally... My db was then in a recovery pending state, I tried running emergency code but it seems pretty broken and i'm not sure 1. why it failed in the first place and 2. what to do now.
Below is the script code and the error message
use school;
DECLARE #TableSchema sys.sysname = N'dbo'
DECLARE #TableName sys.sysname = N'rolerights'
DECLARE #OldTableName sys.sysname = N'rolerigths'
DECLARE #OldTableWithSchema NVARCHAR(256) = QUOTENAME(#TableSchema) + '.' + QUOTENAME(#OldTableName)
DECLARE #TableWithSchema NVARCHAR(256) = QUOTENAME(#TableSchema) + '.' + QUOTENAME(#TableName)
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = #TableSchema
AND TABLE_NAME = #TableName))
BEGIN
EXEC sp_rename #TableWithSchema, #OldTableName
END
DECLARE #Table TABLE ([LogicalName] varchar(128),[PhysicalName] varchar(128), [Type] varchar, [FileGroupName] varchar(128), [Size] varchar(128),
[MaxSize] varchar(128), [FileId]varchar(128), [CreateLSN]varchar(128), [DropLSN]varchar(128), [UniqueId]varchar(128), [ReadOnlyLSN]varchar(128), [ReadWriteLSN]varchar(128),
[BackupSizeInBytes]varchar(128), [SourceBlockSize]varchar(128), [FileGroupId]varchar(128), [LogGroupGUID]varchar(128), [DifferentialBaseLSN]varchar(128), [DifferentialBaseGUID]varchar(128),
[IsReadOnly]varchar(128), [IsPresent]varchar(128), [TDEThumbprint]varchar(128), [SnapshotUrl]varchar(128)
)
DECLARE #Path varchar(1000)='C:\Program Files\Microsoft SQL Server\MSSQL13.SQLEXPRESS\MSSQL\Backup\SQL2008backup.bak'
DECLARE #LogicalNameData varchar(128),#LogicalNameLog varchar(128)
INSERT INTO #table
EXEC('
RESTORE FILELISTONLY
FROM DISK=''' +#Path+ '''
')
SET #LogicalNameData=(SELECT LogicalName FROM #Table WHERE Type='D')
SET #LogicalNameLog=(SELECT LogicalName FROM #Table WHERE Type='L')
SELECT #LogicalNameData, #LogicalNameLog
use master;
declare #MasterData nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer\Parameters', N'SqlArg0', #MasterData output
select #MasterData=substring(#MasterData, 3, 255)
select #MasterData=substring(#MasterData, 1, len(#MasterData) - charindex('\', reverse(#MasterData)))
print #MasterData
print #LogicalNameData
declare #MasterLog nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer\Parameters', N'SqlArg2', #MasterLog output
select #MasterLog=substring(#MasterLog, 3, 255)
select #MasterLog=substring(#MasterLog, 1, len(#MasterLog) - charindex('\', reverse(#MasterLog)))
print #MasterLog
print #LogicalNameLog
declare #DefaultData nvarchar(512)
select isnull(#DefaultData, CONVERT(nvarchar(512), #MasterData))
declare #DefaultLog nvarchar(512)
select isnull(#DefaultLog, CONVERT(nvarchar(512), #MasterLog))
declare #NewDefaultData nvarchar(512) = #MasterData + '\' + 'school.MDF'
declare #NewDefaultLog nvarchar(512) = #MasterLog + '\' + 'school.LDF'
SET DEADLOCK_PRIORITY 10
ALTER DATABASE school
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE school FROM DISK=#Path
WITH MOVE #LogicalNameData TO #NewDefaultData,
MOVE #LogicalNameLog TO #NewDefaultLog,
REPLACE
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = #TableSchema
AND TABLE_NAME = #OldTableName))
BEGIN
EXEC sp_rename #OldTableWithSchema, #TableName
END
And he is the emergency script
ALTER DATABASE [school] SET EMERGENCY;
GO
ALTER DATABASE [school] set single_user
GO
DBCC CHECKDB ([school], REPAIR_ALLOW_DATA_LOSS) WITH ALL_ERRORMSGS;
GO
ALTER DATABASE [school] set multi_user
GO
And the error:
Msg 5069, Level 16, State 1, Line 3
ALTER DATABASE statement failed.
Msg 946, Level 14, State 1, Line 5
Cannot open database 'school' version 677. Upgrade the database to the latest version.
Msg 946, Level 14, State 1, Line 7
Cannot open database 'school' version 677. Upgrade the database to the latest version.
Msg 5069, Level 16, State 1, Line 7
ALTER DATABASE statement failed.
Looking at the original logs... this is why it failed. An exception was thrown about filestream garbage collection apparently...
FILESTREAM Failed to find the garbage collection table.
The way to go into single user mode to restore the master db is to use the -m switch and then restore the master db from SQLCMD. If you want to go into single user mode you probably want to do so using this form:
Set Single_User with rollback immediate;
Please see this page how to use switches at startup:
https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/database-engine-service-startup-options?view=sql-server-2017
I am trying to alter database through a DDL trigger which will fire on creation. However I am getting a below error.
CREATE TRIGGER ddl_trig_database
ON ALL SERVER
FOR CREATE_DATABASE
AS
declare #dbname as nvarchar(100)
declare #sql as nvarchar(max)
select #dbname =
CAST(eventdata().query(
'/EVENT_INSTANCE/DatabaseName[1]/text()'
) as NVarchar(128))
select #sql = N'SET IMPLICIT_TRANSACTIONS OFF
ALTER DATABASE ' + #dbname+ N' SET COMPATIBILITY_LEVEL = 110
SET IMPLICIT_TRANSACTIONS ON'
exec (#sql)
GO
create database test
Error:
Msg 226, Level 16, State 6, Line 22
ALTER DATABASE statement not allowed within multi-statement transaction.
The statement has been terminated.
I am on SQL Server 2014 on Windows 2012.
If you want a specific compatibility level for each new database created - just set that compatibility level in the model database which is the "template" for all new databases being created ...
No need for a system-level trigger for this ....
I realized the DDL trigger will be on its own transaction and Alter is not allowed if a transaction is already started. So to workaround with this problem I have created SQL Job. and put the Alters in the Job and modified the Trigger to call msdb..start_sql_job.
--Trigger
CREATE TRIGGER ddl_trig_database
ON ALL SERVER
FOR CREATE_DATABASE
AS
exec msdb..sp_start_job 'Initialize Database'
GO
--Job
declare #dbname as nvarchar(100)
declare #sql as nvarchar(max)
select top 1 #dbname = name from sys.databases
where name like 'gtp%' and create_date >= getdate() - .08
order by create_date desc
IF #dbname is not null
begin
select #sql = N'ALTER DATABASE ' + #dbname+ N' SET COMPATIBILITY_LEVEL = 110'
exec sp_executesql #sql
print 'Altered database'
end
print 'completed'
I write a simple procedure to shrink database log,just need to input the database name:
ALTER proc [dbo].[sp_shrinkDBAndDBLog]
#databaseName nvarchar(100)
as
begin
declare #logName nvarchar(100),
#dynamicSQL nvarchar(500)
set #dynamicSQL='ALTER DATABASE '+#databaseName+' SET RECOVERY SIMPLE WITH NO_WAIT'
exec(#dynamicSQL)
--select name from HLJEDI_SYS.sys.sysfiles where groupid=0;
set #dynamicSQL=N'select #logName= name from '+#databaseName+'.sys.database_files where type_desc=''LOG'''
exec sp_executesql #dynamicSQL,N'#logName nvarchar(100) output',#logName output
--select * from sys.sysfiles where groupid=0
set #dynamicSQL='DBCC SHRINKFILE (N'''+#logName+''',11,TRUNCATEONLY)'
exec(#dynamicSQL)
--DBCC SHRINKFILE (N'CUC_OA_LOG' , 11, TRUNCATEONLY)
set #dynamicSQL='ALTER DATABASE '+#databaseName+' SET RECOVERY FULL WITH NO_WAIT'
exec(#dynamicSQL)
--ALTER DATABASE OA SET RECOVERY FULL --(Restore to Full Schema)
end
but when i execute with:
exec sp_shrinkDBAndDBLog 'DBName'
it has error:
sys.database_files can't find database 'master' file 'eca2_log'。The file was been deleted and not exists。
And what is the problem? Thank you if you tell me and show the detail and princeple.
Looks like you might be missing a USE { database } command before you execute the DBCC SHRINKFILE command, and so the DBCC is not getting executed on the correct database.
This execution is giving me the following error:
Msg 102, Level 15, State 1, Line 5
Incorrect syntax near 'go'.
Msg 111, Level 15, State 1, Line 11
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.
If i remove the "GO" it gives me just the second one.
Any hints of what am I missing?
declare #dbname varchar(500)
set #dbname='master'
Exec ('
Use ' + #dbname + '
go
create PROCEDURE [dbo].[krijo_database] #dbname nvarchar(2000), #Direktoria varchar(4000)
AS
BEGIN
declare #stringu nvarchar(100)
set #stringu =
''CREATE DATABASE '' + #dbname
exec (#stringu)
End
')
Answer
declare #dbname varchar(500)
set #dbname='kontabel'
Exec(
'Use ' + #dbname +'
Exec (''
create PROCEDURE [dbo].[krijo_database] #dbname nvarchar(2000), #Direktoria varchar(4000)
AS
BEGIN
declare #stringu nvarchar(100)
set #stringu =
''''create DATABASE '''' + #dbname
exec (#stringu)
End
'')
')
Actually I tried like this and it worked but I had to change quotes.
The real procedure that I would like to use is more than 50000 lines and I can't go and manually change the quotes to everything.
Is there a better way?
Two issues:
Using "GO" is incorrect... there is no SQL keyword called "GO"... that's just a hack that SQL Server Management Studio is performing for you.
You need to the CREATE PROCEDURE command in it's own context... simple.
Here's the slight modification to your script:
declare #dbname varchar(500)
set #dbname='master'
Exec ('
Use ' + #dbname + '
EXECUTE(''create PROCEDURE [dbo].[krijo_database] #dbname nvarchar(2000), #Direktoria varchar(4000)
AS
BEGIN
declare #stringu nvarchar(100)
set #stringu =
''''CREATE DATABASE '''' + #dbname
exec (#stringu)
End'')
')
So the answer is to put another "EXECUTE" command inside the first EXECUTE command. I do this all the time, a lot of times in an "sp_msforeachdb". You can nest those bad boys as long as you want.
Sometime ago I had code which was updating database structure based on scripts.
I end up with split file by 'go' and execute separately each fragment. Can you try this?
So, first exec use statement, and than exec createprocedure.
Be sure to verify that it is created in proper database
My mistake, I didn't notice something.
maybe it's the Exec inside the Exec that's causing the error?
or because your'e assigning a nvarchar(2000) to a nvarchar(100)
"Msg 102, Level 15, State 1, Line 5 Incorrect syntax near 'go'. Msg 111, Level 15, State 1, Line 11 'CREATE/ALTER PROCEDURE' must be the first statement in a query batch. " If i remove the "GO" it gives me just the second one.
try this without any use or go: create PROCEDURE '+#dbname+'.[dbo].[krijo_database] #dbname nvarchar(2000)
You can't use GO like that
It isn't a SQL command
It tells SSMS to split the batch
If you remove it, then you'll get "first in batch" error which is expected
In this case, why not just do this...
Use master
GO
create PROCEDURE [dbo].[krijo_database] #dbname nvarchar(2000), #Direktoria varchar(4000)
AS
BEGIN
declare #stringu nvarchar(100)
set #stringu = 'CREATE DATABASE ' + #dbname
exec (#stringu)
End
GO
Why do need dynamic SQL to create a stored procedure?
USE master
GO
CREATE PROCEDURE dbo.create_database #name nvarchar(100)
AS
DECLARE #sql nvarchar(100)
SET #sql = 'CREATE DATABASE ' + QUOTENAME(#name)
EXEC (#sql)
GO
What you're after can't be done I don't think.
See this article for reference
The Real procedure that i would like to use it is a very big one, more dhan 50000 lines and i can't go on an changing the quotes to everything
Microsoft SQL Server has a maximum length of varchar of 8000 characters.
http://www.databasejournal.com/features/mssql/article.php/3788256/Data-Types-in-SQL-Server-2008.htm
you should create stored procedure with that portion with variable.
I used SQl DMO!
Great feature both for 32 and 64 bit,compatible with both SQL express and server!