如何在SQL Server中创建数据库的别名

37

我们有一款非常古老的软件,大约创建于10年前,但我们没有源代码。

该软件使用同一台SQL Server 2012上的两个数据库,DB01DB02

其中存在像db01..table1 join db02..table2这样的SQL语句,但主要问题在于我们的流程不允许使用db02作为数据库名称。

问题是:我们如何为数据库创建别名?

我尝试使用CREATE SYNONYM

CREATE SYNONYM [db02] FOR [db02_new_name];

但对于数据库名称无效。

请提出建议,如何在不修补二进制文件以更正SQL语句的情况下解决该问题。


6
我不相信你能做到。当前的两个答案似乎都没有抓住要点,允许使用服务器实例的别名,并且 SYNONYM 仅适用于数据库内部的对象。我不知道任何别名数据库名称的方法。 - Damien_The_Unbeliever
7个回答

14

使用您想模拟的名称创建一个数据库。重新调整DDL代码生成器,为每个需要通过硬编码名称访问的数据库中的表创建视图。基本上,每个视图将具有类似于以下语句的语句..

CREATE VIEW schemaname.tablename as SELECT * FROM targetdbname.schemaname.tablename

示例:

硬编码的目标数据库名称为 ProdDBV1,而您拥有的源数据库名称为 ProductDatabaseDatabaseV1,模式为 dbo,表名称为 customer

  1. 使用 SSMS 或脚本创建名为 ProdDBV1 的数据库。
  2. CREATE VIEW dbo.customer as SELECT * FROM ProductDatabaseDatabaseV1.dbo.customer

如果您可以枚举“源”数据库中的每个表,然后按照上述方式创建 DDL。如果您需要,我可以使用 sp_msforeachtable 过程更新此发布的代码示例。


假设您有一个调用存储过程的SSRS报表,其中一个参数是数据库名称(假设您有10个不同的客户数据库)- 我认为这种方法无法避免在存储过程中使用动态SQL(即:sp_executesql @sql),其中@sql在运行时连接了数据库名称.....对吗? - tbone
2
这也无法处理函数。:( - tbone
当你说“......我们的流程不允许将db02用作数据库名称”时,为什么这个答案被接受了呢?你是否可以拥有一个名为db02的数据库,它没有数据,但有一堆指向其他数据库的视图? - JeffO

12

我曾经遇到过类似的问题。
使用这个变通方法, 使用同义词解决。

简短版:你要用一个对象的同义词来淹没你的数据库。以后,你可以再用另一个数据库名重新创建每个同义词。


2
哇...这里的人们真是挑剔。Max提供了一个基本正确的答案链接,但似乎因为它提供了链接而不是书面答案而被投票否决? - Jeff Moden
34
当这个博客在几年后消失了呢? - David Roussel
5
在这种情况下,您可以使用Web存档 :-) https://web.archive.org/web/20150502091442/http://www.baud.cz/blog/database-alias-in-microsoft-sql-server - Mladen Mihajlovic
37
普遍认为答案应该是答案,而不是链接到可能包含相关信息的页面。参见:http://meta.stackexchange.com/a/8259 - David Roussel
4
谢谢您的反馈,@DavidRoussel...现在你提到了它,我以前遇到过链接失效的问题,现在我明白了。感谢您的解释。顺便说一下,遇到微软文档中的失效链接真的很令人沮丧(这是一个普遍的问题),所以我特别理解。再次感谢。 - Jeff Moden
1
这个“_workaround_”链接已经失效了。 - intrepidis

5

以下是一个存储过程可以实现这个功能。只需将其添加到数据库中并使用目标数据库调用即可。它将为目标数据库中的所有表创建同义词,如果模式不存在则会创建模式。我已经注释了一部分代码以备不时之需,以便在没有使用游标的情况下获得创建模式的方法。

CREATE PROCEDURE CreateSynonymsForTargetDatabase (
    @databaseName sysname
)
AS BEGIN
DECLARE @TSQL nvarchar(max) = N''
DECLARE @rn char(2),
    @SchemaName sysname;

    SET @rn = char(13) + char(10)   

    CREATE TABLE #DBSynonym(        
        [Schema] sysname NOT NULL,
        [Table] sysname NOT NULL
    )

    SET @TSQL = N'
        INSERT INTO #DBSynonym ([Schema], [Table])
        SELECT Schemas.name, Tables.name
        FROM [' + @databaseName + '].sys.tables 
        INNER JOIN [' + @databaseName + '].sys.schemas on tables.schema_id = schemas.schema_id      
    '

    EXEC (@TSQL)
    SET @TSQL = N''

    DECLARE MissingSchemasCursor CURSOR
    READ_ONLY
    FOR 
        SELECT newSchemas.[Schema]
        FROM #DBSynonym newSchemas
        LEFT JOIN sys.schemas on newSchemas.[Schema] = schemas.name
        WHERE schemas.schema_id is null
        GROUP BY newSchemas.[Schema]

    OPEN MissingSchemasCursor
    FETCH NEXT FROM MissingSchemasCursor INTO @SchemaName
    WHILE (@@fetch_status <> -1)
    BEGIN
        IF (@@fetch_status <> -2)
        BEGIN
            SET @TSQL = N'CREATE SCHEMA ' + QUOTENAME(@SchemaName) + N';'

            EXEC sp_executesql @TSQL
        END
        FETCH NEXT FROM MissingSchemasCursor INTO @SchemaName
    END
    CLOSE MissingSchemasCursor
    DEALLOCATE MissingSchemasCursor

    /*
    SELECT @TSQL = @TSQL +
        N'
        GO
        CREATE SCHEMA ' + QUOTENAME([Schema]) + N';'
    FROM #DBSynonym newSchemas
    LEFT JOIN sys.schemas on newSchemas.[Schema] = schemas.name
    WHERE schemas.schema_id is null
    GROUP BY newSchemas.[Schema]

    PRINT 'CREATE SCHEMAS : ' + ISNULL(@TSQL,'')
    EXEC sp_executesql @TSQL
    */
    SET @TSQL = N''

    SELECT @TSQL = @TSQL +
        N'
        CREATE SYNONYM ' + QUOTENAME([Schema]) + N'.' + QUOTENAME([Table]) + N'
        FOR ' + QUOTENAME(@databaseName) + N'.' + QUOTENAME([Schema]) + N'.' + QUOTENAME([Table]) + N';'
    FROM #DBSynonym


    EXEC sp_executesql @TSQL
    SET @TSQL = N''

END
GO

使用方法如下:

EXEC CreateSynonymsForTargetDatabase 'targetDbName'

1
问题是:我们如何为数据库创建别名?
我知道这是一个旧帖子,但是...这就是为什么我只使用SQL对象的两个部分命名约定。它允许我拥有两部分的同义词,这些同义词取决于我所处的环境而指向命名不同的数据库。虽然有一些地方并不适用,但是大多数情况下这种方法非常有效。
至于那些你没有源代码的软件,如果该软件使用了三部分命名约定,除非你知道每个对象的三部分命名约定并为每个对象创建三部分同义词,否则你可能就无能为力了。

从下票来看,有人严重地错过了重点。甚至原帖发布者也表示他们最终使用了同义词方法。 - Jeff Moden
我同意,这正是我在寻找的,似乎也是 OP 所询问的。 - Marcel Marino
4
虽然这是一篇老贴子,但我怀疑你的回答被踩的原因是它更像是一场讨论和个人偏好,而不是一个解决方案。你没有解释你的术语“2 part synonyms”(我猜你指的是在方案[dbo].[synonym]中局部引用,而不是完全限定的形式,如[server].[database].[schema].[table])。你没有提供示例或解释为什么在数据库中复制同义词比直接引用那些表或将同义词集中在服务器上更好。你的解释只会让正在寻找答案的人更加困惑。 - Antony Booth

0

我发现Charles的答案(以及maxcastaneda在评论中提供的解决方法)非常有用。我按照这种方法操作,它对我很有效。我将其简化了一下,并创建了以下查询,以显示所有需要创建的同义词。

作为此代码片段的先决条件,原始数据库和同义词/别名数据库必须位于同一服务器上,否则如果您使用链接服务器等,则必须稍微修改一下。将其放入小型sp中以自动更新同义词应该相当容易。

USE <SYNONYMDB>
SELECT 
'[' + TABLE_NAME + ']', 
'[' + TABLE_SCHEMA + '].[' + TABLE_NAME + ']',
'IF EXISTS (SELECT * FROM sys.synonyms WHERE name = ''' + TABLE_NAME + ''') DROP SYNONYM ['+ TABLE_NAME + '];   CREATE SYNONYM [' + TABLE_NAME + '] FOR <ORIGINALDB>.' + TABLE_SCHEMA + '.[' + TABLE_NAME + ']' AS SynonymUpdateScript FROM <ORIGINALDB>.INFORMATION_SCHEMA.TABLES

不要忘记在<...>处输入您的数据库名称。

只需复制SynonymUpdateScript列的内容并在同义词数据库中执行它 - 或为此任务创建存储过程。

请注意,如果您有引用表或其他数据库对象而没有使用2部分命名约定的视图,则存在问题。这些同义词将无法工作。您应该在原始对象/视图中修复此问题。


0
  1. 进入您想要创建别名的数据库,

  2. 使用首选设计创建别名文件夹表,

  3. 进入唯一ID表并检查所创建表的最后代码序列。

    例如,如果最后一个代码是10,则将其更新为11。

  4. 打开柜子表,在底部右侧创建您想要的别名柜子名称。


0

3
同样的事情。如果我理解错了,请纠正我,但那似乎是服务器的别名,而不是数据库的别名。 - Jeff Moden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接