Bei einer Ablösung des ERP-Systems oder bei einer Übertragung von Daten einer produktiven Datenbank auf eine Testdatenbank kann es notwendig sein, dass viele Tabellen, Prozeduren, Berechtigungen und Synonyme von einer Datenbank in eine andere übertragen werden müssen. Dieser Blog beschreibt, wie man diese Übertragung mit Hilfe von Prozeduren schnell und unkompliziert gestaltet.
Häufig werden Daten aus Vorsystemen in eine SQL-Server-Datenbank importiert, die als Grundlage für das Modellieren in DeltaMaster dient. Ändert sich das Vorsystem, steht man vor der Aufgabe, die Importdatenbank und Importprozesse auf der SQL-Server-Datenbank anzupassen. Manchmal sind die neuen, zu importierenden Tabellen dabei so stark verändert, dass es unverhältnismäßig wäre, sie anzupassen. In diesem Fall wird man eine neue Importdatenbank aufsetzen müssen.
Die neuen Importtabellen werden zum Beispiel per SSIS in die neue Datenbank importiert. Diese Methodik haben wir unter anderem in einem Beitrag über die dynamische Replikation von Datenbankobjekten beschrieben. Oft gibt es aber zusätzlich zu den importierten Tabellen manuelle Eingabetabellen, welche für das Modell erforderlich sind, aber nicht aus dem Vorsystem importiert werden können. Das können beispielsweise Mapping-Tabellen sein. Entweder belässt man sie auf der alten Importdatenbank und nutzt diese als „Eingabedatenbank“ weiter oder man muss diese Tabellen inklusive der erforderlichen Eingabeprozeduren und Berechtigungen auf die neue Datenbank übertragen. Letzteres kann mit folgenden Prozeduren ausgeführt werden:
- P_APP_Update_Entry_Tables
- P_APP_Copy_Procedures
- P_APP_Copy_Permissions
Nachfolgend beschreiben wir die drei Varianten kurz. Die Prozeduren selbst sind im Anhang angefügt. Die aufgeführten Prozeduren verwenden die Funktion F_BC_Clean_ObjName(). Wenn auf der Datenbank, auf der die jeweilige Prozedur ausgeführt werden soll, kein Delta-Master ETL Modell existiert, ist diese Funktion möglicherweise noch nicht vorhanden. Sollte das der Fall sein, muss diese Funktion auf den entsprechenden Datenbanken zunächst erstellt werden. Sie ist deshalb ebenfalls im Anhang zu finden.
P_APP_Copy_Entry_Tables
Ausgehend davon, dass Eingabetabellen immer mit dem Präfix „T_S“ beginnen, sucht die Prozedur P_APP_Copy_Entry_Tables nach Tabellen, welche mit „T_S“ in der Quelldatenbank beginnen und ersetzt oder erstellt diese in der Zieldatenbank. Sie kann auch dafür verwendet werden, Eingabetabellen von einer produktiven Datenbank auf eine Testumgebung zu kopieren, um die Eingaben nicht doppelt vornehmen zu müssen und die Eingabetabellen trotzdem mit aktuellem Inhalt auf der Testdatenbank verfügbar zu haben.
Die gefundenen Tabellen werden jeweils gelöscht und danach neu erstellt und befüllt. Damit ist gewährleistet, dass Änderungen an der Struktur der jeweiligen Tabellen automatisch mit übernommen werden.
Zum Löschen der Tabellen wird der SQL-Befehl „DROP <table> IF EXISTS“ verwendet. Diese Syntax ist ab SQL-Server 2016 verfügbar.
Soll die Prozedur auf Datenbanken mit niedrigerer Version eingesetzt werden, ist die Zeile
SET @SQL = 'DROP TABLE IF EXISTS ' + @TargetDB + '.' + @TargetSchema + '.' + @tabname
durch
SET @SQL = 'IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_CATALOG = ''' + @TargetDB + ''' AND TABLE_SCHEMA = ''' + @TargetSchema + ''' AND TABLE_NAME = ''' + @tabname + ''')
DROP TABLE ' + @TargetDB + '.' + @TargetSchema + '.' + @tabname
zu ersetzen.
Innerhalb der Prozedur wird geprüft, ob die Parameter Ziel- und Quelldatenbank nicht leer sind und das angegebene Datenbankschema auf der Zieldatenbank existiert.
P_APP_Copy_Procedures
Die Prozedur erstellt die für die Eingabetabellen erforderlichen P_Insert-, P_Update- und P_Delete-Prozeduren auf der Zieldatenbank, wenn diese dort nicht existieren. Dafür werden die entsprechenden Prozeduren aus einer Quelldatenbank gelesen und nach Prüfung, ob diese auf der Zieldatenbank noch nicht existieren, auf der Zieldatenbank erstellt. Vorhandene Prozeduren werden nicht überschrieben.
Innerhalb der Prozedur wird geprüft, ob der Parameter Quelldatenbank nicht leer ist und das angegebene Datenbankschema auf der Zieldatenbank existiert.
Es ist wichtig zu wissen, dass Prozeduren nicht datenbankübergreifend erstellt werden können. Daher ist die Zieldatenbank kein Parameter der Prozedur und die Prozedur muss auf der Zieldatenbank ausgeführt werden.
P_APP_Copy_Permissions
Für das Ausführen der P_Insert-, P_Update- und P_Delete- Prozeduren sind Berechtigungen für die Anwender nötig, welche die Eingaben ausführen sollen. Diese Berechtigungen können ebenfalls mit einer Prozedur von der Quelldatenbank zur Zieldatenbank kopiert werden.
Innerhalb der Prozedur wird geprüft, ob die Parameter Ziel- und Quelldatenbank nicht leer sind und das angegebene Datenbankschema auf der Zieldatenbank existiert.
Das SQL-Statement, welches zum Ermitteln der Berechtigungen verwendet wird, soll hier näher erläutert werden.
SELECT
o.name as objectname,
USER_NAME(p.grantee_principal_id),
p.permission_name
FROM .sys.database_permissions p (NOLOCK)
INNER JOIN .sys.objects o (NOLOCK)
ON p.major_id = o.object_id
INNER JOIN .sys.schemas s
ON o.schema_id = s.schema_id
WHERE p.class = 1
AND s.name =
AND o.type in ('P','U','V')
AND (o.name LIKE '%V_S%' OR o.name LIKE '%T_S%')
AND o.name NOT LIKE '%Model%'
AND o.name NOT LIKE '%SYS%'
AND o.name NOT LIKE 'T_S_TRL%'
AND o.name NOT LIKE 'V_S_CPA%'
AND EXISTS(SELECT * FROM .sys.objects (NOLOCK) sso WHERE sso.name = o.name)
AND EXISTS(SELECT * FROM .sys.database_principals dbp WHERE dbp.name = USER_NAME(p.grantee_principal_id))
AND USER_NAME(grantee_principal_id) <> SYSTEM_USER
ORDER BY o.name, USER_NAME(p.grantee_principal_id), p.permission_name
Es werden der Objektname, der Name des berechtigten Benutzers oder der berechtigten Rolle sowie die Art der Berechtigung aus der Quelldatenbank mit dem SELECT-Statement ermittelt.
Dabei werden in der WHERE-Bedingung nur Objekte (p.class = 1) der Objekttypen Prozedur, Tabelle oder Sicht berücksichtigt (o.type in ('P','U','V')
), welche ein „V_S“ oder „T_S“, im Namen enthalten (o.name LIKE '%V_S%' OR o.name LIKE '%T_S%'
).
Die Berechtigungen nur für die mit der Prozedur „P_APP_Copy_Procedures“ zuvor erstellten Prozeduren zu ermitteln und zu setzen ist oft nicht ausreichend – meist müssen auch Berechtigungen für die mit diesen Prozeduren verknüpften Sichten und Tabellen gesetzt werden. Daher werden auch die entsprechenden Berechtigungen der Sichten und Tabellen mit ermittelt.
Es werden nur Objekte selektiert, welche nicht „SYS“, „Model“, „T_S_TRL“ oder „V_S_CPA%“ im Namen enthalten, da diese von DeltaMaster ETL erstellt und berechtigt werden.
Der eigene User wird ebenfalls ausgeschlossen (USER_NAME(grantee_principal_id) <> SYSTEM_USER
), da davon auszugehen ist, dass man selbst die erforderlichen Berechtigungen besitzt. Ebenfalls wird geprüft, ob das zu berechtigende Objekt auf der Zieldatenbank existiert (EXISTS(SELECT * FROM .sys.objects (NOLOCK) sso WHERE sso.name = o.name)
) sowie ob der zu berechtigende Anwender oder die zu berechtigende Rolle auf der Zieldatenbank vorhanden ist (EXISTS(SELECT * FROM .sys.database_principals dbp WHERE dbp.name = USER_NAME(p.grantee_principal_id))
).
Es ist nicht relevant, ob eine entsprechende Berechtigung auf der Zieldatenbank bereits existiert. Ist dies der Fall, wird die Berechtigung nicht mehrfach angelegt und es wird auch keine Fehlermeldung generiert.
Da bei diesen Selektionsbedingungen auch modellspezifische Prozeduren wie beispielsweise „P_DIM_01_01_Year_01_V_S_Periode“ mit ermittelt werden, wenn diese bereits auf der Zieldatenbank existieren, würden die Berechtigungen der Quelldatenbank für diese Objekte auf die entsprechenden Objekte der Zieldatenbank übertragen. Soll dies nicht erfolgen, ist die WHERE-Bedingung anzupassen.
Zusatzprozedur: P_APP_Copy_Synonyms
Auch Synonyme lassen sich problemlos von einer Datenbank auf eine andere kopieren.
Als kleiner Zusatz zu diesem Artikel ist eine entsprechende Prozedur angehängt. Dabei ist zu beachten, dass beim Erstellen von Synonymen keine Datenbankschemata verwendet werden. Besteht bereits ein Synonym gleichen Namens auf der Zieldatenbank, wird dieses nicht neu angelegt. Die Definition der Synonyme wird nicht verglichen. Es wird auch nicht geprüft, ob das Objekt, auf welches das Synonym referenziert, tatsächlich existiert.
Alle Prozeduren im Überblick
P_APP_Copy_Entry_Tables
CREATE PROC [dbo].[P_APP_Update_Entry_Tables] (@TargetSchema varchar(50) = 'dbo', @SourceSchema varchar(50) = 'dbo', @TargetDB varchar(128)= NULL, @SourceDB varchar(128) = NULL)
AS
SET NOCOUNT ON
DECLARE @SQL nvarchar(4000)
DECLARE @tabname varchar(1000)
DECLARE @ParamDef nvarchar(1000)
DECLARE @schema_id nvarchar(20)
IF LEN(LTRIM(RTRIM(@TargetSchema))) = 0
SET @TargetSchema = 'dbo'
IF LEN(LTRIM(RTRIM(@SourceSchema))) = 0
SET @SourceSchema = 'dbo'
SET @SQL = N'IF EXISTS(SELECT * FROM ' + @TargetDB + '.sys.schemas s WHERE s.name = ''' + @TargetSchema + ''') SET @schemaOUT = 1 ELSE SET @schemaOUT = 0'
SET @ParamDef = N'@schemaOUT nvarchar(20) OUTPUT'
EXEC dbo.sp_executesql @SQL, @ParamDef, @schemaOUT = @schema_id OUTPUT
IF LEN(ISNULL(@SourceDB,'')) = 0 OR
LEN(ISNULL(@TargetDB,'')) = 0 OR
@schema_id = 0
BEGIN
PRINT 'Update_Entry_Tables
The procedure will search for entry tables beginning with T_S in a Source-database and replaces or create them in a Targetdatase.
Please make sure that the specified schema exists on the target database.
For SQL Server 2016 and up.
Parameters:
@TargetSchema - Schema of Targetdatabse tables
@SourceSchema - Schema of Sourcedatabase tables
@TargetDB - Name of Targetdatabase
@SourceDB - Name of Sourcedatabase
Example:
EXEC dbo.P_APP_Update_Entry_Tables @TargetDB = ''Chair_Test'', @SourceDB = ''Chair_Prod'' - Delete, create and fill all tables beginning with T_S on the Targetdata-base that are available on the Sourcedatabase. Both databases are on the same currently selected server and have the schema dbo.
'
END
ELSE
BEGIN
-- Database names in brackets
SET @TargetDB = dbo.F_BC_Clean_ObjName(@TargetDB, 1, 0)
SET @SourceDB = dbo.F_BC_Clean_ObjName(@SourceDB, 1, 0)
-- Tabellencursor
-- It is assumed that tables for manual entry always start with T_S_.
-- The T_S_TRL tables are excluded, since they are created and filled by DeltaMaster ETL.
SET @SQL = '
DECLARE Tab_cursor CURSOR FOR
SELECT
s.name
FROM '
+ @SourceDB + '.sys.objects s (NOLOCK)
WHERE
s.type = ''U''
AND s.name LIKE ''T_S[_]%''
AND s.name NOT LIKE ''T_S_TRL%''
AND s.schema_id = (SELECT sc.schema_id FROM ' + @SourceDB + '.sys.schemas sc (NOLOCK) WHERE sc.name = ''' + @SourceSchema + ''')'
--PRINT @SQL
EXEC sp_executesql @SQL
OPEN Tab_cursor
FETCH NEXT FROM Tab_cursor INTO @tabname
WHILE @@FETCH_STATUS = 0
BEGIN
-- Delete table on Targetdatabase if exists
-- Create and fill table from Sourcedatabase
-- this ensures that changes to the table structure (columns) and content are fully adopted
SET @SQL = 'DROP TABLE IF EXISTS ' + @TargetDB + '.' + @TargetSchema + '.' + @tabname
--PRINT (@SQL)
EXEC (@SQL)
SET @SQL = 'SELECT * INTO ' + @TargetDB + '.' + @TargetSchema + '.' + @tabname + ' FROM ' + @SourceDB + '.' + @SourceSchema + '.' + @tabname
--PRINT(@SQL)
EXEC( @SQL)
FETCH NEXT FROM Tab_cursor INTO @Tabname
END
CLOSE Tab_cursor
DEALLOCATE Tab_cursor
END
P_APP_Copy_Procedures
CREATE PROC [dbo].[P_APP_Copy_Procedures] (@TargetSchema varchar(50) = 'dbo', @SourceSchema varchar(50) = 'dbo', @SourceDB varchar(128) = NULL) AS SET NOCOUNT ON DECLARE @SQL nvarchar(4000) DECLARE @TargetDB varchar(128) DECLARE @text varchar(max) DECLARE @ParamDef nvarchar(1000) DECLARE @schema_id nvarchar(20) IF LEN(LTRIM(RTRIM(@TargetSchema))) = 0 SET @TargetSchema = 'dbo' IF LEN(LTRIM(RTRIM(@SourceSchema))) = 0 SET @SourceSchema = 'dbo' SET @TargetDB = dbo.F_BC_Clean_ObjName(DB_NAME(), 1, 0) SET @SQL = N'IF EXISTS(SELECT * FROM ' + @TargetDB + '.sys.schemas s WHERE s.name = ''' + @TargetSchema + ''') SET @schemaOUT = 1 ELSE SET @schemaOUT = 0' SET @ParamDef = N'@schemaOUT nvarchar(20) OUTPUT' EXEC dbo.sp_executesql @SQL, @ParamDef, @schemaOUT = @schema_id OUTPUT IF LEN(ISNULL(@SourceDB,'')) = 0 OR @schema_id = 0 BEGIN PRINT 'Copy_Procedures The procedure creates procedures for for relational input tables (P_Delete, P_Insert, P_Update) from the Sourcedatabase on the Targetdatase if they don''t exist there. Please make sure that the specified schema exists on the target database. For SQL Server 2016 and up. Since procedures can only be created on the current database, this proce-dure must be executed on the target database. Parameters: @TargetSchema - Schema of Targetdatabse tables @SourceSchema - Schema of Sourcedatabase tables @SourceDB - Name of Sourcedatabase Example: EXEC dbo.P_APP_Copy_Procedures @SourceDB = ''Chair_Prod'' - Create Delta-Master Table Procs (P_Delete, P_Insert, P_Update) from the source database on the current database if they don''t already exist. Both databases are on the same currently selected server, the schema dbo is used. ' END ELSE BEGIN SET @SourceDB = dbo.F_BC_Clean_ObjName(@SourceDB, 1, 0) -- Cursor for Procs -- Only procedures beginning with P_Insert, P_Update, P_Delete will select-ed -- This selection can be changed as required for other kinds of procedures. -- Only procedures that do not exist on the target database are selected. SET @SQL = ' DECLARE cur_proc CURSOR FOR SELECT sc.text FROM ' + @SourceDB + '.sys.objects so (NOLOCK) INNER JOIN ' + @SourceDB + '.sys.syscomments sc (NOLOCK) ON SO.object_id = SC.id WHERE so.type = ''P'' and (So.name LIKE ''P_Delete%'' OR so.name LIKE ''P_Insert%'' OR so.name LIKE ''P_Update%'') AND so.name not LIKE ''%_Model%'' AND so.name not LIKE ''%V_SYS%'' AND NOT EXISTS(SELECT * FROM ' + @TargetDB + '.sys.objects (NOLOCK) sso WHERE sso.type = ''P'' AND sso.name = so.name) AND so.schema_id = (SELECT sch.schema_id FROM ' + @SourceDB + '.sys.schemas sch WHERE sch.name = ''' + @SourceSchema + ''')' --PRINT @SQL EXEC sp_executesql @SQL OPEN cur_proc FETCH NEXT FROM cur_proc into @text WHILE @@FETCH_STATUS = 0 BEGIN SET @SQL = @text EXEC (@SQL) --PRINT @SQL FETCH NEXT FROM cur_proc into @text END CLOSE cur_proc DEALLOCATE cur_proc END
P_APP_Copy_Permissions
CREATE PROC [dbo].[P_APP_Copy_Permissions] (@TargetSchema varchar(50) = 'dbo', @SourceSchema varchar(50) = 'dbo', @TargetDB varchar(128)= NULL, @SourceDB varchar(128) = NULL)
AS
SET NOCOUNT ON
DECLARE @SQL nvarchar(4000)
DECLARE @ParamDef nvarchar(1000)
DECLARE @schema_id nvarchar(20)
DECLARE @objectname varchar(250)
DECLARE @GranteeName varchar(250)
DECLARE @permission varchar(50)
IF LEN(LTRIM(RTRIM(@TargetSchema))) = 0
SET @TargetSchema = 'dbo'
IF LEN(LTRIM(RTRIM(@SourceSchema))) = 0
SET @SourceSchema = 'dbo'
SET @SQL = N'IF EXISTS(SELECT * FROM ' + @TargetDB + '.sys.schemas s WHERE s.name = ''' + @TargetSchema + ''') SET @schemaOUT = 1 ELSE SET @schemaOUT = 0'
SET @ParamDef = N'@schemaOUT nvarchar(20) OUTPUT'
EXEC dbo.sp_executesql @SQL, @ParamDef, @schemaOUT = @schema_id OUTPUT
IF LEN(ISNULL(@SourceDB,'')) = 0 OR
LEN(ISNULL(@TargetDB,'')) = 0 OR
@schema_id = 0
BEGIN
PRINT 'Copy_Permissions
The procedure looks for permissions on tables, views or procedures in the source database and creates them in the target database.
Please make sure that the specified schema exists on the target database.
For SQL Server 2016 and up.
Parameters:
@TargetSchema - Schema of Targetdatabse tables
@SourceSchema - Schema of Sourcedatabase tables
@TargetDB - Name of Targetdatabase
@SourceDB - Name of Sourcedatabase
Example:
EXEC dbo.P_APP_Copy_Permissions @TargetDB = ''Chair_Test'', @SourceDB = ''Chair_Prod'' - Create permissions on objects on the target database that are available on the source database. Both databases are on the same current server, the schema dbo is used.
'
END
ELSE
BEGIN
-- Database names in brackets
SET @TargetDB = dbo.F_BC_Clean_ObjName(@TargetDB, 1, 0)
SET @SourceDB = dbo.F_BC_Clean_ObjName(@SourceDB, 1, 0)
-- Get permissions on objects (p.class = 1) on the source database
-- Only objects which do not contain SYS, Model, T_S_TRL or V_S_CPA in their name, as these are created and authorized by DeltaMaster ETL
-- or which are of table, view, or procedure type ( o.type in ('P','U','V'))
-- and which ones exist on the target database on which the permissions are to be set
SET @SQL = 'DECLARE cur_perm CURSOR FOR
SELECT
o.name as objectname
, USER_NAME(p.grantee_principal_id)
, p.permission_name
FROM ' + @SourceDB + '.sys.database_permissions p (NOLOCK)
INNER JOIN ' + @SourceDB + '.sys.objects o (NOLOCK)
ON p.major_id = o.object_id
INNER JOIN ' + @SourceDB + '.sys.schemas s
ON o.schema_id = s.schema_id
WHERE p.class = 1
AND s.name = ''' + @SourceSchema +
''' AND o.type in (''P'',''U'',''V'')
AND (o.name LIKE ''%V_S%'' OR o.name LIKE ''%T_S%'')
AND o.name not LIKE ''%SYS%''
AND o.name NOT LIKE ''%Model%''
AND o.name NOT LIKE ''T_S_TRL%''
AND o.name NOT LIKE ''V_S_CPA%''
AND EXISTS(SELECT * FROM ' + @TargetDB + '.sys.objects (NOLOCK) sso WHERE sso.name = o.name)
AND EXISTS(SELECT * FROM ' + @TargetDB + '.sys.database_principals dbp WHERE dbp.name = USER_NAME(p.grantee_principal_id))
AND USER_NAME(grantee_principal_id) <> SYSTEM_USER -- eigenen User ausschließen
ORDER BY o.name, USER_NAME(p.grantee_principal_id), p.permission_name'
--PRINT @SQL
EXEC sp_executesql @SQL
OPEN cur_perm
FETCH NEXT FROM cur_perm INTO @objectname, @GranteeName, @permission
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = 'USE ' +@TargetDB + ' GRANT ' + @permission + ' ON ' + @TargetSchema + '.' + @objectname + ' TO [' + @GranteeName + ']'
--PRINT (@SQL)
EXEC(@SQL)
FETCH NEXT FROM cur_perm INTO @objectname, @GranteeName, @permission
END
CLOSE cur_perm
DEALLOCATE cur_perm
END
Zusatzprozedur: P_APP_Copy_Synonyms
CREATE PROC [dbo].[P_APP_CreateSynonyms] (@TargetDB varchar(128) = NULL, @SourceDB varchar(128) = NULL)
AS
SET NOCOUNT ON
DECLARE @synname varchar(250)
DECLARE @base_object varchar(500)
DECLARE @SQL nvarchar(2000)
IF LEN(ISNULL(@SourceDB,'')) = 0
OR LEN(ISNULL(@TargetDB,'')) = 0
BEGIN
PRINT 'P_APP_CreateSynonyms
The procedure will search for differences in synonyms between a Sourcedatabase and teh current database.
Parameters:
@TargetDB - Name of Targetdatabase
@SourceDB - Name of Sourcedatabase
Examples:
EXEC dbo.P_APP_CreateSynonyms @TargetDB = ''Chair_Test'', @SourceDB = ''Chair_Prod'' - Create all synonyms that are available on the Sourcedatabase but not on the Targetdatabase. Both databases are on the same currently selected server.
'
END
ELSE
BEGIN
-- Database names in brackets
SET @TargetDB = dbo.F_BC_Clean_ObjName(@TargetDB, 1, 0)
SET @SourceDB = dbo.F_BC_Clean_ObjName(@SourceDB, 1, 0)
-- Select synonyms of Source database
-- Replacing the source database name with the target database name
SET @SQL = 'DECLARE cur_syn CURSOR FOR
SELECT
stest.name
, REPLACE(stest.base_object_name,''' + @SourceDB + ''',''' + @TargetDB +''')
FROM ' + @SourceDB + '.sys.synonyms stest (NOLOCK)
WHERE LEFT(stest.name,1) in (''T'',''V'',''S'')
AND stest.name not LIKE ''%Model%''
AND NOT EXISTS(SELECT * FROM ' + @TargetDB + '.sys.synonyms sprod WHERE sprod.name = stest.name)'
--PRINT @SQL
EXEC sp_executesql @SQL
open cur_syn
FETCH NEXT FROM cur_syn INTO @synname, @base_object
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = 'USE ' + @TargetDB + ' CREATE SYNONYM ' + @synname + ' For ' + @base_object
--PRINT @SQL
EXEC (@SQL)
FETCH NEXT FROM cur_syn INTO @synname, @base_object
END
CLOSE cur_syn
DEALLOCATE cur_syn
END
F_BC_Clean_Objectname
CREATE FUNCTION [dbo].[F_BC_Clean_ObjName] (@ObjName varchar(150), @AddBracket bit = 1, @AddDot bit = 0)
RETURNS varchar(150)
BEGIN
DECLARE @RetVal varchar(150)
SET @RetVal = isnull(replace(replace(CASE WHEN right(@ObjName, 1) = '.' AND len(@ObjName) > 1 THEN left(@ObjName, len(@ObjName)-1) WHEN @ObjName = '.' THEN @@servername ELSE @ObjName END , '[', ''), ']', ''), '')
SELECT @RetVal = CASE WHEN @AddBracket = 1 and @RetVal <> '' THEN '[' ELSE '' END + @RetVal + CASE WHEN @AddBracket = 1 and @RetVal <> '' THEN ']' ELSE '' END + CASE WHEN @AddDot = 1 and @RetVal <> '' THEN '.' ELSE '' END
RETURN @RetVal
END