Reputation: 5355
I have production database (for example, PROD1
). It has a lot of synonyms to another database (for example, PROD2
).
I have created PROD2_TEST
(as fully copy of PROD2
) and also PROD1_TEST
(as full copy of PROD1
). But as a result I have PROD1_TEST
synonyms to PROD2
, instead of PROD2_TEST
.
How, can I automatically recreate all synonyms to the test database?
Upvotes: 7
Views: 19938
Reputation: 315
Made a change to @kuklei 's answer to fix synonyms whose local name is different from the object they are referencing. Also, allow multiple replaces at once with a temp table (please replace the values in the "insert into #Replacements" section with the replacements you want to make):
create table #Replacements
(
SearchString varchar(100)
,OldPrefix varchar(100)
,NewPrefix varchar(100)
)
insert into #Replacements
values
('_productiondb%','[productiondb]','[not_productiondb]') -- renamed local db
,('_192.168.100.1_._productdb%','[192.168.100.1].[productdb]','[productdb]') -- Moved db from remote to local
,('_192.168.100.1_._reportdb%','[192.168.100.1].[reportdb]','[not_reportdb]') -- renamed remote db
SELECT
dropSynonym =
'DROP SYNONYM ['
+ SCHEMA_NAME(schema_id)
+ '].['
+ name
+ '];'
,createSynonym =
' CREATE SYNONYM ['
+ SCHEMA_NAME(schema_id)
+ '].['
+ name
+ '] FOR '
+ REPLACE(base_object_name,OldPrefix,NewPrefix)
,synonymName =
'['
+ SCHEMA_NAME(schema_id)
+ '].['
+ name
+ ']'
,oldSynonymTarget = base_object_name
,newPrefix
FROM sys.synonyms s
left join #Replacements r
on s.base_object_name like r.SearchString
order by
createSynonym
drop table #Replacements
Upvotes: 0
Reputation: 1205
Based on @artm suggestion I expanded it just a little bit to include parameters to make it more generic. Here is the code
DECLARE @newDB VARCHAR(MAX) = 'newDB', --newDB to point the synonym to
@linkedSrv VARCHAR(MAX) = null --if the synonym points to a linked server than specify it here like '[LinkedSrv].' (including the dot in the end)
SELECT 'Drop Synonym [' + SCHEMA_NAME(schema_id) + '].[' + PARSENAME(base_object_name, 1) + '];' AS dropSynonym,
' CREATE SYNONYM [' + SCHEMA_NAME(schema_id) + '].[' + UPPER(PARSENAME(base_object_name, 1)) + '] FOR '
+ COALESCE(@linkedSrv, '') + '[' + @newDB + '].[' + COALESCE(PARSENAME(base_object_name, 2),
SCHEMA_NAME(SCHEMA_ID())) + '].['
+ UPPER(PARSENAME(base_object_name, 1)) + '];' AS createSynonym
FROM sys.synonyms`
Upvotes: 14
Reputation: 8584
I've had to do this for the same reasons and this is the query I used. Run the query, copy paste the results to the new server (PROD_Test) and run the produced queries. It handles different schema names and multiple databases in case you're using them:
SELECT 'Drop Synonym [' + SCHEMA_NAME(schema_id) + '].[' + PARSENAME(base_object_name,1) + '];CREATE SYNONYM [' +
SCHEMA_NAME(schema_id) + '].[' + PARSENAME(base_object_name,1) + '] FOR [' + COALESCE(PARSENAME(base_object_name,3),DB_NAME(DB_ID())) + '_Test].['
+ COALESCE(PARSENAME(base_object_name,2),SCHEMA_NAME(SCHEMA_ID())) + '].[' + PARSENAME(base_object_name,1) + '];'
FROM sys.synonyms
Upvotes: 5
Reputation: 1036
Here's something I used to remap all synonyms to a new database on the same server (based on Tobsey's suggestion)
SET NOCOUNT ON;
DECLARE @db_name SYSNAME
DECLARE @schema_name SYSNAME
DECLARE @cmd NVARCHAR(256)
SET @schema_name = N'dbo'
SET @db_name = N'[newdb]'
DECLARE @schema_id INT
SELECT @schema_id = schema_id
FROM sys.schemas
WHERE NAME = @schema_name;
DECLARE @table_list TABLE (table_name SYSNAME,dest_table_name sysname,dest_schema_name sysname)
DECLARE @table_name SYSNAME
declare @dest_table_name sysname
declare @dest_schema_name sysname
DECLARE @prefix NVARCHAR(50)
DECLARE @synonym SYSNAME
DECLARE @linked_server SYSNAME
SET @linked_server = N'SERVER'
-- create a synonym for these tables (insert each table)
INSERT INTO @table_list (table_name,dest_table_name,dest_schema_name)
SELECT name
,'['+SUBSTRING(name,CHARINDEX('.',name,CHARINDEX('.',name,0)+1)+1,LEN(name)-CHARINDEX('.',name,CHARINDEX('.',name,0)+1))+']'
,SUBSTRING(name,CHARINDEX('.',name,0)+1,CHARINDEX('.',name,CHARINDEX('.',name,0)+1)-CHARINDEX('.',name,0)-1)
FROM sys.synonyms
WHERE base_object_name LIKE '![SERVER!].![olddb!]%' ESCAPE ('!')
ORDER BY name
IF EXISTS (
SELECT *
FROM sys.servers
WHERE NAME = @linked_server
)
-- 4 part name
SET @prefix = @linked_server + N'.' + @db_name
ELSE
-- 3 part name
SET @prefix = @db_name
SELECT TOP 1 @table_name = table_name,@dest_table_name = dest_table_name,@dest_schema_name=dest_schema_name
FROM @table_list
WHILE @table_name IS NOT NULL
BEGIN
-- set the schema and name for the synonym
SET @synonym = @schema_name+ N'.' + '['+@table_name+']'
-- delete the synonym if it exists
IF EXISTS (
SELECT *
FROM sys.synonyms
WHERE NAME = @table_name
AND schema_id = @schema_id
)
BEGIN
SET @cmd = N'drop synonym ' + @synonym
PRINT @cmd
--EXEC sp_executesql @cmd
END
-- create the synonym
SET @cmd = N'create synonym ' + @synonym + N' for ' + @prefix + N'.'+ @dest_schema_name + N'.'+ @dest_table_name
PRINT @cmd
--EXEC sp_executesql @cmd
PRINT 'GO'
DELETE TOP (1)
FROM @table_list
SET @table_name = NULL
SELECT TOP 1 @table_name = table_name,@dest_table_name = dest_table_name,@dest_schema_name=dest_schema_name
FROM @table_list
END
GO
Upvotes: 1
Reputation: 3400
It is not possible to alter a synonym, you will have to drop and create them. The following article contains a script to create synonyms for a range of tables. Hopefully you can modify it to suit your needs:
Use synonyms to abstract SQL Server objects
You can view all of the existing synonyms using the sys.synonyms
view. In pseudocode what you want to do is:
name
and base_object_name
PROD2
to PROD2_TEST
Upvotes: 1