i have construct a dynamic sql and it is bit big. so when i am trying to execute it then i am getting error like
Msg 156, Level 15, State 1, Procedure sp_InstallListenerNotification_1, Line 31
Incorrect syntax near the keyword 'END'.
Msg 102, Level 15, State 1, Procedure sp_InstallListenerNotification_1, Line 118
Incorrect syntax near 'END'.
i am not being able to find out where is the problem and where to fix. so help me to compile it if possible. here is my dynamic sql script.
DECLARE #msg VARCHAR(MAX)
DECLARE #crlf CHAR(1)
SET #crlf = CHAR(10)
SET #msg = 'Current user must have following permissions: '
SET #msg = #msg + '[CREATE PROCEDURE, CREATE SERVICE, CREATE QUEUE, SUBSCRIBE QUERY NOTIFICATIONS, CONTROL, REFERENCES] '
SET #msg = #msg + 'that are required to start query notifications. '
SET #msg = #msg + 'Grant described permissions with following script: ' + #crlf
SET #msg = #msg + 'GRANT CREATE PROCEDURE TO [<username>];' + #crlf
SET #msg = #msg + 'GRANT CREATE SERVICE TO [<username>];' + #crlf
SET #msg = #msg + 'GRANT CREATE QUEUE TO [<username>];' + #crlf
SET #msg = #msg + 'GRANT REFERENCES ON CONTRACT::[DEFAULT] TO [<username>];' + #crlf
SET #msg = #msg + 'GRANT SUBSCRIBE QUERY NOTIFICATIONS TO [<username>];' + #crlf
SET #msg = #msg + 'GRANT CONTROL ON SCHEMA::[<schemaname>] TO [<username>];'
PRINT #msg
IF OBJECT_ID ('[bba-reman].sp_InstallListenerNotification_1', 'P') IS NULL
BEGIN
EXEC ('
CREATE PROCEDURE [bba-reman].sp_InstallListenerNotification_1
AS
BEGIN
-- Service Broker configuration statement.
-- Setup Service Broker
IF EXISTS (SELECT * FROM sys.databases
WHERE name = ''bbareman'' AND (is_broker_enabled = 0 OR is_trustworthy_on = 0))
BEGIN
IF (NOT EXISTS(SELECT * FROM sys.fn_my_permissions(NULL, ''SERVER'')
WHERE permission_name = ''CONTROL SERVER''))
BEGIN
DECLARE #msg VARCHAR(MAX)
SET #msg = ''Current user doesn''''t have CONTROL SERVER permission to enable service broker. ''
SET #msg = #msg + ''Grant sufficient permissions to current user or ''
SET #msg = #msg + ''execute ALTER DATABASE [<dbname>] SET ENABLE_BROKER with admin rights.''
RAISERROR (#msg, 16, 1)
END
ELSE
BEGIN
--ALTER DATABASE [bbareman] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
--ALTER DATABASE [bbareman] SET ENABLE_BROKER;
--ALTER DATABASE [bbareman] SET MULTI_USER WITH ROLLBACK IMMEDIATE
-- FOR SQL Express
--ALTER AUTHORIZATION ON DATABASE::[bbareman] TO [sa]
--ALTER DATABASE [bbareman] SET TRUSTWORTHY ON;
END
END
-- Create a queue which will hold the tracked information
IF NOT EXISTS (SELECT * FROM sys.service_queues WHERE name = ''ListenerQueue_1'')
CREATE QUEUE [bba-reman].[ListenerQueue_1]
-- Create a service on which tracked information will be sent
IF NOT EXISTS(SELECT * FROM sys.services WHERE name = ''ListenerService_1'')
CREATE SERVICE [ListenerService_1] ON QUEUE [bba-reman].[ListenerQueue_1] ([DEFAULT])
-- Notification Trigger check statement.
IF OBJECT_ID (''[bba-reman].tr_Listener_1'', ''TR'') IS NOT NULL
RETURN;
-- Notification Trigger configuration statement.
DECLARE #triggerStatement NVARCHAR(MAX)
DECLARE #select NVARCHAR(MAX)
DECLARE #sqlInserted NVARCHAR(MAX)
DECLARE #sqlDeleted NVARCHAR(MAX)
SET #triggerStatement = N''
CREATE TRIGGER [tr_Listener_1]
ON [bba-reman].[ContentChangeLog]
AFTER INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
--Trigger ContentChangeLog is rising...
IF EXISTS (SELECT * FROM sys.services WHERE name = ''''ListenerService_1'''')
BEGIN
DECLARE #message NVARCHAR(MAX)
SET #message = N''''<root/>''''
IF ( EXISTS(SELECT 1))
BEGIN
DECLARE #retvalOUT NVARCHAR(MAX)
%inserted_select_statement%
IF (#retvalOUT IS NOT NULL)
BEGIN SET #message = N''''<root>'''' + #retvalOUT END
%deleted_select_statement%
IF (#retvalOUT IS NOT NULL)
BEGIN
IF (#message = N''''<root/>'''') BEGIN SET #message = N''''<root>'''' + #retvalOUT END
ELSE BEGIN SET #message = #message + #retvalOUT END
END
IF (#message != N''''<root/>'''') BEGIN SET #message = #message + N''''</root>'''' END
END
--Beginning of dialog...
DECLARE #ConvHandle UNIQUEIDENTIFIER
--Determine the Initiator Service, Target Service and the Contract
BEGIN DIALOG #ConvHandle
FROM SERVICE [ListenerService_1] TO SERVICE ''''ListenerService_1'''' ON CONTRACT [DEFAULT] WITH ENCRYPTION=OFF, LIFETIME = 60;
--Send the Message
SEND ON CONVERSATION #ConvHandle MESSAGE TYPE [DEFAULT] (#message);
--End conversation
END CONVERSATION #ConvHandle;
END
''
SET #select = STUFF((SELECT '','' + COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = ''ContentChangeLog'' AND TABLE_CATALOG = ''bbareman''
FOR XML PATH ('''')
), 1, 1, '''')
SET #sqlInserted =
N''SET #retvalOUT = (SELECT '' + #select + N''
FROM INSERTED
FOR XML PATH(''''row''''), ROOT (''''inserted''''))''
SET #sqlDeleted =
N''SET #retvalOUT = (SELECT '' + #select + N''
FROM DELETED
FOR XML PATH(''''row''''), ROOT (''''deleted''''))''
SET #triggerStatement = REPLACE(#triggerStatement
, ''%inserted_select_statement%'', #sqlInserted)
SET #triggerStatement = REPLACE(#triggerStatement
, ''%deleted_select_statement%'', #sqlDeleted)
EXEC sp_executeSql #triggerStatement
END
')
END
You can't have an empty BEGIN ...END block. You need to add at least one executable statement, for example a PRINT
BEGIN
--ALTER DATABASE [bbareman] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
--ALTER DATABASE [bbareman] SET ENABLE_BROKER;
--ALTER DATABASE [bbareman] SET MULTI_USER WITH ROLLBACK IMMEDIATE
-- FOR SQL Express
--ALTER AUTHORIZATION ON DATABASE::[bbareman] TO [sa]
--ALTER DATABASE [bbareman] SET TRUSTWORTHY ON;
PRINT 'Dummy Output'
END
It also looks like you are missing an END. You need three END statements after the dummy PRINT.
Related
I want to write a script, its function is to create a stored procedure and before create it the script should have to check if it exists in DB, so I write the procedure like below, If I comment out first 2 lines the scripts will create procedure successfully if the stored procedure not exist, but I add the first two lines, the SSMS will throw error:
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[User_Own_Restore_From_Job]') AND type in (N'P'))
CREATE PROCEDURE [dbo].[User_Own_Restore_From_Job]
#dbname varchar(500),
#backuppath varchar (500)
AS
BEGIN
SET NOCOUNT ON
DECLARE #XPConfig int = 1
--To keep the existing value
SELECT #XPConfig = cast(value AS INT) FROM sys.configurations WHERE name LIKE 'xp_cmdshell';
--Enabling xp_cmdshell for getting registry and creating directory structure
BEGIN TRY
EXEC sp_configure 'show advanced options', 1
RECONFIGURE with override
-- To enable the feature.
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE with override
END TRY
BEGIN CATCH
--empty
END CATCH
DECLARE #datapath nvarchar(500);
DECLARE #logpath nvarchar(500);
--read data and log path details from registry
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\Setup', N'SQLDataRoot', #datapath OUTPUT
EXECUTE master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'DefaultLog', #logpath OUTPUT
SET #datapath=#datapath+'\Data';
--creating a database folder if not already exists on log and data drives
DECLARE #datapath2 varchar(500)=''
DECLARE #logpath2 varchar(500)=''
SET #DataPath2 = #datapath+ N'\'+#dbname
SET #LogPath2 = #logpath+ N'\'+#dbname
--reading all folders from DATA directory
DECLARE #DirTree TABLE (subdirectory nvarchar(255), depth INT)
INSERT INTO #DirTree(subdirectory, depth)
EXEC master.sys.xp_dirtree #DataPath
--creating a folder on DATA drive with database name if not already exists
IF NOT EXISTS (SELECT 1 FROM #DirTree WHERE subdirectory = #DBName)
EXEC master.dbo.xp_create_subdir #DataPath2
DELETE FROM #DirTree
--reading all folders from LOG directory
INSERT INTO #DirTree(subdirectory, depth)
EXEC master.sys.xp_dirtree #LogPath
--creating a folder on LOG drive with database name if not already exists
IF NOT EXISTS (SELECT 1 FROM #DirTree WHERE subdirectory = #DBName)
EXEC master.dbo.xp_create_subdir #LogPath2
DECLARE #PhysicalName nvarchar(260)=''
DECLARE #LogicalName nvarchar(128)=''
DECLARE #Type char(1)=''
DECLARE #text nvarchar(2000)=''
DECLARE #sql nvarchar(max)=''
DECLARE #restoredb TABLE ( LogicalName nvarchar(128), PhysicalName nvarchar(260),Type char(1)
,FileGroupName nvarchar(128),Size numeric(20,0),MaxSize numeric(20,0),FileID bigint,CreateLSN numeric(25,0),DropLSN numeric(25,0)
,UniqueID uniqueidentifier,ReadOnlyLSN numeric(25,0),ReadWriteLSN numeric(25,0),BackupSizeInBytes bigint,SourceBlockSize int
,FileGroupID int,LogGroupGUID uniqueidentifier,DifferentialBaseLSN numeric(25,0),DifferentialBaseGUID uniqueidentifier
,IsReadOnly bit,IsPresent bit,TDEThumbprint varbinary(32),SnapshotUrl nvarchar(128))
--reading header section of backup file
INSERT #restoredb EXECUTE(N'RESTORE FILELISTONLY FROM DISK = '''+#backuppath +'''')
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
BEGIN TRY
--***taking backup of all permissions**********************************
CREATE TABLE #Permissions (id int identity(1,1), qry nvarchar(4000),Stat bit default 0)
SET #sql='USE ['+#dbname+'];
-- Create Users If not exists
INSERT INTO #Permissions (qry)
select
txt=case when isnull(l.name,'''')=''''
then ''IF NOT EXISTS (SELECT 1 FROM sys.database_principals where name = '''''' + p.name + '''''') BEGIN CREATE USER ['' + p.name +''] FOR LOGIN ['' + p.name +''] END''
else ''IF NOT EXISTS (SELECT 1 FROM sys.database_principals where name = '''''' + p.name + '''''') BEGIN CREATE USER ['' + p.name +''] FOR LOGIN ['' + l.name +''] END''
end
from sys.database_principals p
left join master..syslogins l on l.sid = p.sid
where p.type NOT IN (''R'') AND p.name NOT IN (''dbo'',''guest'',''INFORMATION_SCHEMA'',''sys'')
UNION ALL
--Create Role If not exists
select
txt=case when isnull(l.name,'''')=''''
then ''IF NOT EXISTS (SELECT 1 FROM sys.database_principals where name = '''''' + p.name + '''''') BEGIN CREATE Role ['' + p.name +''] END''
else ''''
end
from sys.database_principals p
left join master..syslogins l on l.sid = p.sid
where p.type =''R'' and p.name NOT IN (''dbo'',''guest'',''INFORMATION_SCHEMA'',''sys'',
''db_owner'',''db_accessadmin'',''db_securityadmin'',''db_ddladmin'',''db_backupoperator'',''db_datareader'',''db_datawriter'',''db_denydatareader'',''db_denydatawriter'',''public'')
UNION ALL
--User Permissions
select
txt=case when isnull(p.type ,'''')<>''G''
then ''ALTER USER ['' + p.name +''] WITH DEFAULT_SCHEMA = ''+ isnull(p.default_schema_name, ''[NULL]'') +'';''
else ''''
end
+ '' EXEC sp_addrolemember '''''' + q.name + '''''', '''''' + p.name + '''''';''
from sys.database_principals p
join (select * from sys.database_principals a
join sys.database_role_members r on a.principal_id=r.role_principal_id) q
on q.member_principal_id = p.principal_id
where (p.type NOT IN (''R'')) AND p.name NOT IN (''dbo'',''guest'',''INFORMATION_SCHEMA'',''sys'')
UNION ALL
--Orphaned users
select
txt=case when isnull(l.name,'''')=''''
then ''Exec sp_change_users_login ''''update_one'''', '''''' + p.name + '''''', '''''' + p.name + '''''' ''
else ''Exec sp_change_users_login ''''update_one'''', '''''' + p.name + '''''', '''''' + l.name + '''''' ''
end
from sys.database_principals p
left join master..syslogins l on l.sid = p.sid
where p.type=''S'' AND p.name NOT IN (''dbo'',''guest'',''INFORMATION_SCHEMA'',''sys'')
'
--get all permissions in text format
EXECUTE sp_executesql #sql
--**Permissions end******************************************************************--
--**preparing a restore statement****************************************************--
SET #SQL='USE [master];ALTER DATABASE ['+#dbname+N'] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE ['+#dbname+N'] SET SINGLE_USER;
ALTER DATABASE ['+#dbname+N'] set offline with NO_WAIT;'
--set database to single user mode
EXECUTE sp_executesql #sql
SET #SQL='RESTORE DATABASE ['+#dbname+N'] FROM DISK = '''+#backuppath+''' WITH FILE = 1'
--preparing move statement for all files
DECLARE c1 CURSOR FOR SELECT PhysicalName,LogicalName,Type FROM #restoredb
OPEN c1;
FETCH NEXT FROM c1 INTO #PhysicalName,#LogicalName,#Type -- fetch first value
WHILE ##fetch_status = 0
BEGIN
SET #text = RIGHT(#PhysicalName,CHARINDEX( '\', REVERSE(#PhysicalName)));
SET #SQL=#SQL+', MOVE '''+#LogicalName+N''''
IF (#Type = 'L')
SET #SQL=#SQL+' TO '''+#logpath+N'\'+#dbname+#text+N''''
ELSE
SET #SQL=#SQL+' TO '''+#datapath+N'\'+#dbname+#text+N''''
FETCH NEXT FROM c1 INTO #PhysicalName,#LogicalName,#Type -- fetch next value
END; --WHILE ##fetch_status = 0
CLOSE c1
DEALLOCATE c1;
-- replace ersetzt die alte db
SET #SQL=#SQL+', NOUNLOAD , replace , STATS = 10 ;'
--perform restore database operation
EXECUTE sp_executesql #sql
--setting database to online mode
SET #SQL='USE [master];
ALTER DATABASE ['+#dbname+N'] set ONLINE with NO_WAIT;
ALTER DATABASE ['+#dbname+N'] SET MULTI_USER; '
EXECUTE sp_executesql #sql
-- changes database owner to sa
SET #SQL='USE [' + #dbname + N'];
EXEC sp_changedbowner ''sa'' '
EXECUTE sp_executesql #sql
--**Database a restore is completed**********************************************--
--**restore permissions on database****************************************************--
DECLARE #ptxt nvarchar(4000)='',#Id int=0
WHILE 0=0
BEGIN
SELECT #ptxt='',#Id=0
SELECT TOP 1 #Id=Id, #ptxt=qry FROM #Permissions WHERE Stat=0 ORDER BY Id
IF Isnull(#Id,0)<=0 BREAK;
SET #ptxt= N'USE [' + #dbname + N'];' + #ptxt
--skip if any invalid login/user exists
BEGIN TRY
--print #ptxt
EXECUTE (#ptxt)
END TRY
BEGIN CATCH
--No action is needed
END CATCH
UPDATE #Permissions SET Stat=1 WHERE Id=#Id
END
END TRY
BEGIN CATCH
--setting database to online mode
SET #SQL='USE [master];
ALTER DATABASE ['+#dbname+N'] set ONLINE with NO_WAIT;
ALTER DATABASE ['+#dbname+N'] SET MULTI_USER; '
EXECUTE sp_executesql #sql
SELECT #ErrorMessage = ERROR_MESSAGE(), #ErrorSeverity = ERROR_SEVERITY(), #ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, -- Message text.
#ErrorSeverity, -- Severity.
#ErrorState -- State.
);
END CATCH
BEGIN TRY
EXEC sp_configure 'show advanced options', 1
RECONFIGURE with override
--Retain original setting
EXEC sp_configure 'xp_cmdshell', #XPConfig
RECONFIGURE with override
END TRY
BEGIN CATCH
SELECT #ErrorMessage = ERROR_MESSAGE(), #ErrorSeverity = ERROR_SEVERITY(), #ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, -- Message text.
#ErrorSeverity, -- Severity.
#ErrorState -- State.
);
END CATCH
END
The error message like below:
Msg 156, Level 15, State 1, Line 4
Incorrect syntax near the keyword 'PROCEDURE'.
Msg 137, Level 15, State 2, Line 69
Must declare the scalar variable "#dbname".
Msg 137, Level 15, State 2, Line 70
Must declare the scalar variable "#dbname".
Msg 137, Level 15, State 2, Line 79
Must declare the scalar variable "#DBName".
Msg 137, Level 15, State 2, Line 90
Must declare the scalar variable "#DBName".
Msg 137, Level 15, State 2, Line 105
Must declare the scalar variable "#backuppath".
Msg 137, Level 15, State 2, Line 116
Must declare the scalar variable "#dbname".
Msg 137, Level 15, State 2, Line 177
Must declare the scalar variable "#dbname".
Msg 137, Level 15, State 2, Line 184
Must declare the scalar variable "#dbname".
Msg 137, Level 15, State 2, Line 198
Must declare the scalar variable "#dbname".
......
can anyone explain this for me how to fix this issue if I want to have a pre-check?
CREATE PROCEDURE has to be the only statement in a batch. To conditionally execute it, you can use dynamic SQL.
...
IF ...
BEGIN
EXECUTE(N'CREATE PROCEDURE ...');
END;
...
If you only need the conditional execution to prevent errors of the procedure already existing and your version of SQL Server is high enough, you can alternatively use the CREATE OR ALTER PROCEDURE ... statement. It's available since 2016, I believe. That way the procedure simply gets overwritten, if it already exists, without the statement throwing any errors because of the procedure already existing.
Basically the constraint is 'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.
Depends on what you want, there are several option, each has different effect.
CREATE OR ALTER PROCEDURE
create or alter procedure [dbo].[User_Own_Restore_From_Job]
as
begin
...
end;
GO
the effect is the procedure is altered and the modify_date in sys.procedures will be updated every time it executes
DROP PROCEDURE + CREATE PROCEDURE
If you are using a earlier version of SQL Server without the CREATE OR ALTER option, you can check for existence of the store procedure, drop it and create it.
if object_id('dbo.User_Own_Restore_From_Job') is not null
drop procedure dbo.User_Own_Restore_From_Job
GO
create procedure [dbo].[User_Own_Restore_From_Job]
as
begin
...
end;
GO
the effect is the procedure is drop and create everytime it executes. And also the create_date and modify_date will be change also.
Don't execute if exists
this make use of set noexec settings. If the procedure exists set noexec to off (The subsequent commands will not be executed). And set it back to on at the end.
IF object_id('dbo.User_Own_Restore_From_Job') is not null
set noexec on;
GO
create procedure [dbo].[User_Own_Restore_From_Job]
as
begin
...
end;
GO
set noexec off;
I have sp in MSSQL server - code below. When I run it from job, or SSMS it runs OK. But I need to run it from VB6 app with ADODB.
My VB6 code:
Dim cmd As New ADODB.Command
cmd.ActiveConnection = CNN
cmd.CommandTimeout = 180
cmd.CommandText = "dbbackup"
cmd.CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
cmd.Execute(, , ADODB.ConnectOptionEnum.adAsyncConnect)
Problem is: When database backup is almost done - about 90+%, cmd.State changes from Executing to Closed and VB6 code continue in executing (to this moment it waits for sp to complete). But there is a lot of code after backup which never run this way(old backup delete,...). I realized that “Last database backup” property on MSSQL database was not set and in table msdb.dbo.backupset there are no rows for my backup. But there si good restorable backup on HDD.
When i stops program for 5 minutes in debug, sp runs properly to end and everything is OK. This backup code is last code in app run and after it ends program closes all connections and exits. I added wait to VB6 code and it helps on some servers, but many other servers still has same problem.
I think main question is why MSSQL server returns control flow to VB6 code and sp is not completed yet.
Thanks
sp code:
PROCEDURE [dbo].[dbBackup]
AS
BEGIN
SET NOCOUNT ON;
EXEC sp_configure 'show advanced options', 1
RECONFIGURE
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE
If OBJECT_ID('tempdb..#DBName','u') IS NULL
Create Table #DBName
(
ID int identity (1,1) ,
Name varchar(128) not null ,
RetentionPeriod int null,
BackupPath varchar(255) default(''),
DBSize float default(0)
)
If OBJECT_ID('tempdb..#ExistingBackups', 'u') IS NULL
Create Table #ExistingBackups
(
Name varchar(128) ,
ID int identity (1,1)
)
Declare #Path varchar(255)
Declare #sql varchar(1000)
Declare #Name varchar(128)
Declare #RetentionPeriod int
Declare #LastBackupToKeep varchar(8)
Declare #ID int
Declare #MaxID int
Declare #eName varchar(255)
Declare #eMaxID int
Declare #eID int
Declare #eTimeStamp varchar(20)
Declare #errMsg nvarchar(2048)
Declare #errCount int; set #errCount = 0;
Declare #freeSpace bigint
Declare #pageSize float
Declare #dbSize bigint
Declare #procDate datetime
Declare #Sklad char(3)
Declare #backupName as varchar(255)
Select #pageSize = v.low / 1024 From master..spt_values v (noLock) Where v.number = 1 And v.[type] = 'E'
Select Top 1 #sklad = sklad_id From dbo.pohyb (noLock) Where Convert(int, sklad_id) > 500
Set #procDate = GETDATE()
Truncate Table #DBName
Insert Into #DBName (Name, RetentionPeriod, BackupPath)
Select DBName, BackupsToStore, BackupPath
From dbo.databaseBackup (noLock)
Where runBackup = 1
Select #MaxID = max(ID), #ID = 0 From #DBName
While #ID < #MaxID
Begin
Select #ID = min(ID) From #DBName Where ID > #ID
Select #Name = Name, #RetentionPeriod = RetentionPeriod, #Path = BackupPath
From #DBName
Where ID = #ID
If SUBSTRING(#Path, Len(#Path), 1) <> '\' Set #Path = #Path + '\'
Set #sql = 'Update #DBName Set DBSize= (Select Round(Sum(size) *' + CONVERT(varchar, #pageSize) + '/1024, 0) From ' + #Name + '.dbo.sysfiles (noLock)) Where Name = ''' + #Name + ''''
Exec (#sql)
Select #dbSize = DBSize From #DBName
--Exec #freeSpace = dbo.getDiskFreeSpace #drive = #Path
--If #freeSpace > #dbSize
--Begin
Set #eTimeStamp = REPLACE(REPLACE(CONVERT(varchar, #procDate, 113), ' ', '_'), ':', '-')
Set #sql = #Path + #Name + '_' + #eTimeStamp + '.bak'
Set #errMsg = 'OK'
Begin Try
SET #backupName = 'Objednavky backup by job ' + CONVERT(varchar, GETDATE(), 104) + ' ' + CONVERT(varchar, GETDATE(), 108);
Backup Database #Name To Disk = #sql
WITH NAME = #backupName;
-------mazanie backupu begin
Truncate Table #ExistingBackups
Set #sql = 'dir /B /OD ' + #Path + #Name + '_*.bak'
Insert #ExistingBackups Exec master..xp_cmdshell #sql
If Exists (Select 1 From #ExistingBackups Where PATINDEX('%File Not Found%', Name) > 0)
Truncate Table #ExistingBackups
Delete From #ExistingBackups Where Name IS NULL
Select #eID = 0
Select #eMaxID = Max(ID) - #RetentionPeriod From #ExistingBackups
While #eID < #eMaxID
Begin
Select #eID = Min(ID) From #ExistingBackups Where ID > #eID
Select #eName = Name From #ExistingBackups Where ID = #eID
Set #sql = 'del ' + #Path + #eName
Exec master..xp_cmdshell #sql
End
Truncate Table #ExistingBackups
-------mazanie backupu end
End Try
Begin Catch
Set #errMsg = #errMsg + '||' + CONVERT(varchar,ERROR_MESSAGE())
Set #errCount = #errCount + 1;
End Catch
--End
--Else
--Set #errMsg = 'Pln? disk (Vo?n? miesto: ' + CONVERT(varchar, #freeSpace) + ' MB, potrebn? aspo?: ' + CONVERT(varchar, #dbSize) + ' MB)'
Insert Into [dbo].[databaseBackup_log] ([Sklad_id], [DBName], [BackupDate], [Status]) Values (#Sklad, #Name, #procDate, Ltrim(Rtrim(CONVERT(varchar,#errMsg))))
End
Drop Table #DBName
Drop Table #ExistingBackups
IF #errCount > 0 BEGIN
RAISERROR (#errMsg, 16, 2) WITH SETERROR
END
RETURN 0;
END
I want to pass table name as parameter and I want to that parameter in where clause
CREATE PROC [dbo].[bb_GetPrepositionInfo]
#userid INT,#propId INT,#tabName varchar(50)
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRAN
SELECT *
FROM #tblname
WHERE ([acq_id] = #propId AND [user_id] = #userid)
COMMIT
GO
Not tested but You need to use Dynamic SQL.
CREATE PROC [dbo].[bb_GetPrepositionInfo]
#userid INT,#propId INT,#tabName varchar(50)
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRAN
DECLARE #SQL varchar(250)
SELECT #SQL = 'SELECT * FROM ' + QuoteName(#tabName) + ' where acq_id=' + Quotename(#propId) + ' AND user_id=' + Quotename(#userid)
EXEC (#SQL)
COMMIT
GO
CREATE PROC [dbo].[bb_GetPrepositionInfo]
DECLARE #userid INT
DECLARE #propId INT
DECLARE #tabName varchar(50)
DECLARE #sqlCommand varchar(200)
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRAN
SET #sqlCommand = 'SELECT * from ' + #tabName +'WHERE [acq_id]='+ #propId +'AND [user_id] = '+ #userid
EXEC (#sqlCommand)
COMMIT
GO
Say I want to run the following:
update users set age = 10
on databases:
db1, db2, db3
All on the same server, I want to loop through and perform the same action.
Currently I am doing this manually using management studio via the dropdown.
Hoping there is a better way.
You could probably do it with dynamic SQL. Something like so:
create table #dbs (db_name sysname not null)
insert into #dbs values ('db1'),('db2'),('db3')
declare curs cursor for
select db_name from #dbs
declare #db sysname, #sql nvarchar(max)
open curs
while(1=1)
begin
fetch next from curs into #db
if (##fetch_status <> 0)
break
set #sql = 'update ' + quotename(#db) + '.dbo.users set age = 10'
exec(#sql)
end
close curs
deallocate curs
drop table #dbs
Not sure about doing it 'dynamically', i.e. a FOR-EACH style loop on all the databases in a server, but this should work:
USE db1
update users set age = 10
GO
USE db2
update users set age = 10
GO
USE db3
update users set age = 10
Designate a server as a central management server and then add the other servers to the server group. Then you can run the update on all databases within the group. http://msdn.microsoft.com/en-us/library/bb934126.aspx
use [WWAUTHxxx__] -- a db containing active databases.
set nocount on
declare #Catalog as nvarchar(32)
declare #LibraryName as varchar(255)
declare #dbtable as varchar(50)
declare #retval as nvarchar(50)
declare #sSQL as nvarchar(max)
declare #parmdef as nvarchar(500)
declare #retvalout as nvarchar(50)
Declare Library_Cursor Cursor for
select top(1000) xCatalog, xLibraryName
from Active_DBs
order by xcatalog
Open Library_Cursor;
Fetch Next from Library_Cursor into #Catalog, #LibraryName
while ##Fetch_status = 0
begin
set #dbTable = #Catalog + '.dbo.las_circperiods'
set #ParmDef = N'#retvalOUT int OUTPUT';
set #sSQL = N'Select #retvalout = count(*) from ' + #dbtable
+ ' where xlastcircdate is null'
exec sp_executesql #ssql,#parmdef,#retvalout=#retval output
if #retval > 0 -- check/print Sql and then activate.
-- I like checking to see the potentially affected databases.
begin
print #Catalog + ',' + #LibraryName + ',' + #retval
set #ssql = N'update ' + #dbTable
+ ' set xlastcircdate = '''' '
+ ' where xlastcircdate is null'
-- print #ssql -- View what you might will do
exec sp_executesql #ssql -- Do it.
end
Fetch Next from Library_Cursor into #Catalog, #LibraryName
end;
close Library_cursor
Deallocate Library_cursor
(Note this question asks about linking ALL Users, unlike the possible duplicate that asks about linking a single user)
I wish to move a database between two servers, I have backed the database up from the first server and done a database restore on the 2nd server, so far so good.
However our application makes use of a lot of database users that are defined in the database. These have to be linked to logins that are defined in the master database. The server I have restored the database to has all the logins defined, however they have different sids.
I am not a T-SQL expert….
I think sp_change_users_login is part of the solution, but I can't find out how to get it to automatically link all users in the restored database to the login of the same name.
The database creation scripts we use for our application create the users and logins, however it does not specify the SID when creating the login, hence this problem. Now if I had a time machine...
(When I Google I get lots of hits, however they are mostly sites that won't let you see the answer without having to register on the site first.)
Yes, you can do that by executing:
EXEC sp_change_users_login 'Auto_Fix' , 'TheUserName';
However if your question was can I fix all users automatically then this won't do that.
I came up with the following. It works great because it shows you:
All the current orphaned users.
Which ones were fixed.
Which ones couldn't be fixed.
Other solutions require you to know the orphaned user name before hand in order to fix.
The following code could run in a sproc that is called after restoring a database to another server.
Script:
EXEC sp_change_users_login 'report'--See all orphaned users in the database.
DECLARE #OrphanedUsers TABLE
(
IndexKey Int IDENTITY(1,1) PRIMARY KEY,
UserName SysName,--nVarChar(128)
UserSID VarBinary(85)
)
INSERT INTO #OrphanedUsers
EXEC sp_change_users_login 'report'
DECLARE #CRLF as nVarChar
SET #CRLF = CHAR(10) + '&' + CHAR(13)--NOTE: Carriage-Return/Line-Feed will only appear in PRINT statements, not SELECT statements.
DECLARE #Sql as nVarChar(MAX)
SET #Sql = N''
DECLARE #IndexKey as Int
SET #IndexKey = 1
DECLARE #MaxIndexKey as Int
SET #MaxIndexKey = (SELECT COUNT(*) FROM #OrphanedUsers)
DECLARE #Count as Int
SET #Count = 0
DECLARE #UsersFixed as nVarChar(MAX)
SET #UsersFixed = N''
DECLARE #UserName as SysName--This is an orphaned Database user.
WHILE (#IndexKey <= #MaxIndexKey)
BEGIN
SET #UserName = (SELECT UserName FROM #OrphanedUsers WHERE IndexKey = #IndexKey)
IF 1 = (SELECT COUNT(*) FROM sys.server_principals WHERE Name = #UserName)--Look for a match in the Server Logins.
BEGIN
SET #Sql = #Sql + 'EXEC sp_change_users_login ''update_one'', [' + #UserName + '], [' + #UserName + ']' + #CRLF
SET #UsersFixed = #UsersFixed + #UserName + ', '
SET #Count = #Count + 1
END
SET #IndexKey = #IndexKey + 1
END
PRINT #Sql
EXEC sp_executesql #Sql
PRINT 'Total fixed: ' + CAST(#Count as VarChar) + '. Users Fixed: ' + #UsersFixed
SELECT ('Total fixed: ' + CAST(#Count as VarChar) + '. Users Fixed: ' + #UsersFixed)[Fixed]
EXEC sp_change_users_login 'report'--See all orphaned users still in the database.
Result:
*Note: The 4 that were not fixed (in my example screenshot above) did not have a corresponding User in the destination Server that the database was restored to.
If:
EXEC sp_change_users_login 'Auto_Fix' , 'TheUserName';
Doest't work, try this:
EXEC sp_change_users_login 'Auto_Fix', 'Username', NULL, 'p#ssword123'
I found it here:
http://dbadiaries.com/using-sp_change_users_login-to-fix-sql-server-orphaned-users
I found the following script from Microsoft KB918992 - run it on the original server and it will create a stored procedure called 'sp_help_revlogin' which generates another script to run on the destination server, creating all user accounts with the same passwords and sids. Worked wonders for our upgrade from SQL2000 to 2008.
USE master
GO
IF OBJECT_ID ('sp_hexadecimal') IS NOT NULL
DROP PROCEDURE sp_hexadecimal
GO
CREATE PROCEDURE sp_hexadecimal
#binvalue varbinary(256),
#hexvalue varchar(256) OUTPUT
AS
DECLARE #charvalue varchar(256)
DECLARE #i int
DECLARE #length int
DECLARE #hexstring char(16)
SELECT #charvalue = '0x'
SELECT #i = 1
SELECT #length = DATALENGTH (#binvalue)
SELECT #hexstring = '0123456789ABCDEF'
WHILE (#i <= #length)
BEGIN
DECLARE #tempint int
DECLARE #firstint int
DECLARE #secondint int
SELECT #tempint = CONVERT(int, SUBSTRING(#binvalue,#i,1))
SELECT #firstint = FLOOR(#tempint/16)
SELECT #secondint = #tempint - (#firstint*16)
SELECT #charvalue = #charvalue +
SUBSTRING(#hexstring, #firstint+1, 1) +
SUBSTRING(#hexstring, #secondint+1, 1)
SELECT #i = #i + 1
END
SELECT #hexvalue = #charvalue
GO
IF OBJECT_ID ('sp_help_revlogin') IS NOT NULL
DROP PROCEDURE sp_help_revlogin
GO
CREATE PROCEDURE sp_help_revlogin #login_name sysname = NULL AS
DECLARE #name sysname
DECLARE #xstatus int
DECLARE #binpwd varbinary (256)
DECLARE #txtpwd sysname
DECLARE #tmpstr varchar (256)
DECLARE #SID_varbinary varbinary(85)
DECLARE #SID_string varchar(256)
IF (#login_name IS NULL)
DECLARE login_curs CURSOR FOR
SELECT sid, name, xstatus, password FROM master..sysxlogins
WHERE srvid IS NULL AND name <> 'sa'
ELSE
DECLARE login_curs CURSOR FOR
SELECT sid, name, xstatus, password FROM master..sysxlogins
WHERE srvid IS NULL AND name = #login_name
OPEN login_curs
FETCH NEXT FROM login_curs INTO #SID_varbinary, #name, #xstatus, #binpwd
IF (##fetch_status = -1)
BEGIN
PRINT 'No login(s) found.'
CLOSE login_curs
DEALLOCATE login_curs
RETURN -1
END
SET #tmpstr = '/* sp_help_revlogin script '
PRINT #tmpstr
SET #tmpstr = '** Generated '
+ CONVERT (varchar, GETDATE()) + ' on ' + ##SERVERNAME + ' */'
PRINT #tmpstr
PRINT ''
PRINT 'DECLARE #pwd sysname'
WHILE (##fetch_status <> -1)
BEGIN
IF (##fetch_status <> -2)
BEGIN
PRINT ''
SET #tmpstr = '-- Login: ' + #name
PRINT #tmpstr
IF (#xstatus & 4) = 4
BEGIN -- NT authenticated account/group
IF (#xstatus & 1) = 1
BEGIN -- NT login is denied access
SET #tmpstr = 'EXEC master..sp_denylogin ''' + #name + ''''
PRINT #tmpstr
END
ELSE BEGIN -- NT login has access
SET #tmpstr = 'EXEC master..sp_grantlogin ''' + #name + ''''
PRINT #tmpstr
END
END
ELSE BEGIN -- SQL Server authentication
IF (#binpwd IS NOT NULL)
BEGIN -- Non-null password
EXEC sp_hexadecimal #binpwd, #txtpwd OUT
IF (#xstatus & 2048) = 2048
SET #tmpstr = 'SET #pwd = CONVERT (varchar(256), ' + #txtpwd + ')'
ELSE
SET #tmpstr = 'SET #pwd = CONVERT (varbinary(256), ' + #txtpwd + ')'
PRINT #tmpstr
EXEC sp_hexadecimal #SID_varbinary,#SID_string OUT
SET #tmpstr = 'EXEC master..sp_addlogin ''' + #name
+ ''', #pwd, #sid = ' + #SID_string + ', #encryptopt = '
END
ELSE BEGIN
-- Null password
EXEC sp_hexadecimal #SID_varbinary,#SID_string OUT
SET #tmpstr = 'EXEC master..sp_addlogin ''' + #name
+ ''', NULL, #sid = ' + #SID_string + ', #encryptopt = '
END
IF (#xstatus & 2048) = 2048
-- login upgraded from 6.5
SET #tmpstr = #tmpstr + '''skip_encryption_old'''
ELSE
SET #tmpstr = #tmpstr + '''skip_encryption'''
PRINT #tmpstr
END
END
FETCH NEXT FROM login_curs INTO #SID_varbinary, #name, #xstatus, #binpwd
END
CLOSE login_curs
DEALLOCATE login_curs
RETURN 0
GO
List of all orphan user details with corresponding DB name
Simple step
EXEC master.sys.sp_MSforeachdb ' USE [?]
Select ''?''
EXEC ?.dbo.sp_change_users_login ''report'' '
I have a nice script that you can use to create logins from database users,which I came across after searching for this issue this script is using a stored procedure. you can find some other useful scripts here also at this url
http://www.sqlserveroptimizer.com/2011/08/how-to-script-logins-from-user-database-in-sql-server-20052008-r2/
USE MyDatabaseName
DECLARE #login nvarchar(50)
DECLARE logins_cursor CURSOR FOR SELECT l.name FROM sys.database_principals u INNER JOIN sys.server_principals l ON u.sid=l.sid
OPEN logins_cursor FETCH NEXT FROM logins_cursor INTO #login
WHILE ##FETCH_STATUS = 0 BEGIN EXEC sp_help_revlogin #login FETCH NEXT FROM logins_cursor INTO #login END
CLOSE logins_cursor DEALLOCATE logins_cursor GO