如何重命名物理数据库文件

18

我使用 TSQL 分离数据库,方法如下:

EXEC sp_detach_db @dbname = 'my_db'

我随后使用PHP重命名物理文件。我能够重命名mdf文件,但无法重命名ldf文件!我甚至尝试了一个dos命令REN,但这对ldf文件也不起作用!

我想问一下,物理日志文件是否有什么特殊之处,导致它无法被重命名?

有没有更好的方法来完成这个任务?

谢谢大家


第一个问题是,你为什么要尝试做这件事? - Lazarus
我正在尝试进行适当的重命名。自从我分离了一个数据库以后,我无法使用相同的名称创建一个数据库,因为物理文件名仍然相同。 - Abs
相关 更改SQL数据库名称 - James Jenkins
7个回答

20

将数据库分离、重命名文件,再次附加。


唯一需要注意的是,在执行分离操作之前,请记下与您的数据库相关联的.mdf、.ndf和.ldf文件的路径和文件名。如果您有多个数据库在同一默认SQL Server安装位置创建其数据、辅助数据和日志文件,则在重新附加数据库时可能会感到困惑。 - RBT
4
您可以使用SSM图形用户界面进行分离操作,使用Windows资源管理器重命名文件,但您需要使用TSQL重新附加。请参考链接:重命名SQL数据库的方法MSDN上的重新附加指南 - James Jenkins
对于在Linux上使用SQL Server的任何人,您可能需要使用命令行中的sqlcmd工具按照Microsoft文档重新附加。我尝试通过SSMS,但没有成功。 - The Thirsty Ape
我发现这种简单的方法有效(SSMS 2012),不需要根据其他建议运行脚本或进行其他任何操作。 - Fandango68
可能以前的版本能运行,但不包括第15版。 - Gustav

16
  1. 备份原始数据库
  2. 删除原始数据库
  3. 使用备份文件恢复原始数据库,但使用不同的名称;恢复的数据库文件将自动采用新的数据库名称。

3
太简单了!谢谢。 - MikeZ
由于某种原因,逻辑文件名保持不变(在我的情况下),但这并不是问题,因为物理文件名确实发生了变化。 - Brains
这对我完全没有起作用。 - Doug Kimzey

10

"ALTER DATABASE (your database) MODIFY FILE" 命令只会重命名逻辑名称。本文介绍如何使用 xp_cmdshell 也重命名物理文件:http://www.mssqltips.com/sqlservertip/1891/best-practice-for-renaming-a-sql-server-database/

请注意以下事项:
1. xp_cmdshell 将在 SQL Server 进程运行的用户下执行,并可能没有所需的文件系统权限来重命名数据库文件。
2. 出于安全原因,请记得禁用 xp_cmdshell。

以下是根据上述博客文章进行重命名的示例。它将用数据库 NewMyDB 替换数据库 MyDB。原始的 MyDB(重命名为 MyDB_OLD)将被保留为分离状态。

-- Enable xp_cmdshell:
sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE
GO
sp_configure 'xp_cmdshell', 1
RECONFIGURE WITH OVERRIDE
GO

-- Get physical file names:
declare @MyDBOriginalFileName nvarchar(300) = (select physical_name FROM sys.master_files where name = 'MyDB')
declare @MyDBLogOriginalFileName nvarchar(300) = (select physical_name FROM sys.master_files where name = 'MyDB_log')
declare @NewMyDBOriginalFileName nvarchar(300) = (select physical_name FROM sys.master_files where name = 'NewMyDB')
declare @NewMyDBLogOriginalFileName nvarchar(300) = (select physical_name FROM sys.master_files where name = 'NewMyDB_log')
declare @Command nvarchar(500)
declare @Sql nvarchar(2000)

IF (EXISTS (select * from sys.databases where name = 'NewMyDB') 
AND EXISTS (select * from sys.databases where name = 'MyDB'))
BEGIN
    USE master

    ALTER DATABASE MyDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE
    ALTER DATABASE NewMyDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE

        -- Set new database name
        ALTER DATABASE MyDB MODIFY NAME = MyDB_OLD
        ALTER DATABASE NewMyDB MODIFY NAME = MyDB

        -- Update logical names
        ALTER DATABASE MyDB_OLD MODIFY FILE (NAME=N'MyDB', NEWNAME=N'MyDB_OLD')
        ALTER DATABASE [MyDB] MODIFY FILE (NAME=N'NewMyDB', NEWNAME=N'MyDB')

        EXEC master.dbo.sp_detach_db @dbname = N'MyDB_Old'
        EXEC master.dbo.sp_detach_db @dbname = N'MyDB'

        -- Rename physical files
        SET @Command = 'RENAME "' + @MyDBOriginalFileName + '" "MyDB_OLD.mdf"'; PRINT @Command
        EXEC xp_cmdshell @Command
        SET @Command = 'RENAME "' + @MyDBLogOriginalFileName + '" "MyDB_OLD_log.mdf"'; PRINT @Command
        EXEC xp_cmdshell @Command
        SET @Command = 'RENAME "' + @NewMyDBOriginalFileName + '" "MyDB.mdf"'; PRINT @Command
        EXEC xp_cmdshell @Command
        SET @Command = 'RENAME "' + @NewMyDBLogOriginalFileName + '" "MyDB_log.mdf"'; PRINT @Command
        EXEC xp_cmdshell @Command

        -- Attach with new file names
        declare @NewMyDBFileNameAfterRename nvarchar(300) = replace(@NewMyDBOriginalFileName, 'NewMyDB',  'MyDB')
        declare @NewMyDBLogFileNameAfterRename nvarchar(300) = replace(@NewMyDBOriginalFileName, 'NewMyDB_log',  'MyDB_log')
        SET @Sql = 'CREATE DATABASE MyDB ON ( FILENAME = ''' + @NewMyDBFileNameAfterRename + '''), ( FILENAME = ''' + @NewMyDBLogFileNameAfterRename + ''') FOR ATTACH'
        PRINT @Sql
        EXEC (@Sql)

    ALTER DATABASE MyDB SET MULTI_USER 

END

-- Disable xp_cmdshell for security reasons:
GO
sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE
GO
sp_configure 'xp_cmdshell', 0
RECONFIGURE WITH OVERRIDE
GO

1
请在您的回答中附上一些从提供的链接中提取/总结的内容。链接本身不是答案。而且...链接可能会过时。 - Radim Köhler

9
您可以使用 ALTER DATABASE 语句来完成 - 就像这样:
ALTER DATABASE database_name
   MODIFY FILE ( NAME = logical_file_name, 
                 FILENAME = ' new_path/os_file_name_with_extension ' )

您需要单独修改每个文件,例如,如果您有多个数据文件,您需要修改每个文件。

详细信息请参阅Technet文档


为了让这实际起作用,我必须手动移动文件或重命名文件,对吗? SQL Server 不会为我完成此操作,这就是我试图自动化的部分。 - Abs
4
执行上述命令后,您需要将数据库切换为离线状态,对文件进行物理重命名,然后将其切换回在线状态。 - ulath

8

重命名 SQL Server 物理数据库文件 最简单的方法是:

  1. 打开并连接到包含要重命名的数据库的 SQL Server
  2. 在查询窗口中执行以下脚本,以更改物理和逻辑名称。记得将所有 "OldDatabaseName" 替换为你想要将其名称更改为的数据库的新名称 ("NewDatabaseName")。替换所有的 NewDatabaseName 为你想要为数据库设置的新名称。

use OldDatabaseName

ALTER DATABASE OldDabaseName MODIFY FILE (NAME='OldDatabaseName', FILENAME='C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\NewDatabaseName.mdf');

ALTER DATABASE OldDatabaseName MODIFY FILE (NAME='OldDatabaseName_log', FILENAME='C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\NewDatabaseName_log.ldf');

ALTER DATABASE OldDatabaseName MODIFY FILE (NAME = OldDatabaseName, NEWNAME = NewDatabaseName);
ALTER DATABASE OldDatabaseName MODIFY FILE (NAME = OldDatabaseName_log, NEWNAME = NewDatabaseName_log);
  1. 然后右键单击 OldDatabaseName,选择 Tasks,然后选择 Take Offline

  2. 转到物理文件位置(C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\...),将它们重命名为您在第2步中指定的NewDatabaseName。请记住检查这些文件的绝对路径是否适用于您的计算机。
  3. 返回到 Microsoft SQL Server Management Studio。右键单击 OldDatabaseName,选择 Tasks,然后选择 Bring Online
  4. 最后,将您的OldDatabaseName重命名为NewDatabaseName。完成啦 :-)

你也可以执行 ALTER DATABASE NewDatabaseName SET OFFLINE,然后在执行 ALTER DATABASE NewDatabaseName SET ONLINE 之前进行文件名更改。 - cusman
只是说文件 'oldname' 不存在。 - niico
只有当SSMS可以访问DATA文件夹时,这才能正常工作。 - Gustav

2
  1. 分离数据库(右键单击数据库)

  2. 重命名两个文件(ldf和mdf): C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA

  3. 附加数据库(右键单击顶部文件夹“Databases”)

enter image description here


1
哇 - 我真希望我能让这个工作... - Doug Kimzey
可能之前的版本可以用,但是15版不行。 - Gustav

0

我偶然发现了这个旧帖子,但是没有一个答案完全符合我的要求,而且我不知道为什么忽略了Sverre的回答。由于我需要清理很多可怕的不一致的低版本SQL服务器数据库文件位置并合并磁盘/文件夹结构,所以我整理了这个代码。希望能对某些人有所帮助。

-- create a script that generates necessary commands to relocate a set of databases from
-- one location to another and some other stuff
-- 1) offline database
-- 2) alter databases modify files
-- 3) generates OS file move commands
-- 3.5) includes renaming the files to match database AND file type/enumeration
-- 4) online databaases databases using create database for attach commands

--== declare some configuration variavbles ==--
DECLARE @newpath            SYSNAME = 'G:\DefaultInstance\QA'
DECLARE @databasewildcard   SYSNAME = '%_NEW'

--== start with a commands table ==--
IF OBJECT_ID('tempdb..#commands') IS NOT NULL DROP TABLE #commands
CREATE TABLE #commands ([id] INT IDENTITY, [command] VARCHAR(MAX))

IF OBJECT_ID('tempdb..#excludedatabases') IS NOT NULL DROP TABLE #excludedatabases
CREATE TABLE #excludedatabases ([id] INT IDENTITY, [database] SYSNAME)

INSERT INTO #excludedatabases ([database]) VALUES ('exceptiondatabase_NEW')

--== insert commands : offline databases ==--
INSERT INTO #commands ([command])
    SELECT
     --'EXEC master.dbo.sp_detach_db @dbname = N' + QUOTENAME(sd.[name],'''')+ ';'
     'USE [master]; ALTER DATABASE ' + QUOTENAME(sd.[name]) + ' SET OFFLINE WITH ROLLBACK IMMEDIATE;'
    FROM sys.databases sd
    WHERE sd.[name] LIKE @databasewildcard
    AND sd.[name] NOT IN    (SELECT
                             ed.[database]
                            FROM #excludedatabases ed)

--== insert commands : modify logical physical file name ==--
INSERT INTO #commands ([command])   
    SELECT
     'ALTER DATABASE ' + QUOTENAME(sd.[name]) + ' MODIFY FILE (NAME = N' + QUOTENAME(smf.[name],'''') + ', FILENAME = N' + QUOTENAME(@newpath + '\'
                                                                    +   CASE
                                                                            WHEN smf.[type_desc] = 'ROWS'   THEN sd.[name] + '_data_file' + RIGHT('00' + CAST(smf.[file_id] AS VARCHAR),2) + '.mdf'
                                                                            WHEN smf.[type_desc] = 'LOG'    THEN sd.[name] + '_log_file' + RIGHT('00' + CAST(smf.[file_id] AS VARCHAR),2) + '.ldf'
                                                                        END
                                                                    ,'''') + ');'
    FROM sys.master_files smf
    JOIN sys.databases sd ON smf.[database_id] = sd.[database_id]
    WHERE sd.[name] LIKE @databasewildcard
    AND sd.[name] NOT IN    (SELECT
                             ed.[database]
                            FROM #excludedatabases ed)

--== insert commands : generate OS move commands ==--
INSERT INTO #commands ([command]) VALUES ('/* --===== comment out these commands as a block - execute in file system =====--')

INSERT INTO #commands ([command])
    SELECT
     --'MOVE ' + QUOTENAME(smf.[physical_name],'"') + ' ' + QUOTENAME(@newpath + '\','"') AS [command]
     'MOVE ' + QUOTENAME(smf.[physical_name],'"') + ' ' + QUOTENAME(@newpath + '\'
                                                                    +   CASE
                                                                            WHEN smf.[type_desc] = 'ROWS'   THEN sd.[name] + '_data_file' + RIGHT('00' + CAST(smf.[file_id] AS VARCHAR),2) + '.mdf'
                                                                            WHEN smf.[type_desc] = 'LOG'    THEN sd.[name] + '_log_file' + RIGHT('00' + CAST(smf.[file_id] AS VARCHAR),2) + '.ldf'
                                                                        END
                                                                    ,'"') AS [command]
    FROM sys.master_files smf
    JOIN sys.databases sd ON smf.[database_id] = sd.[database_id]
    WHERE sd.[name] LIKE @databasewildcard
    AND sd.[name] NOT IN    (SELECT
                             ed.[database]
                            FROM #excludedatabases ed)

INSERT INTO #commands ([command]) VALUES ('*/ --===== comment out these commands as a block - execute in file system =====--')

--== insert commands : online databases ==--
INSERT INTO #commands ([command])
    SELECT
     'USE [master]; ALTER DATABASE ' + QUOTENAME(sd.[name]) + ' SET ONLINE WITH ROLLBACK IMMEDIATE;'
    FROM sys.databases sd
    WHERE sd.[name] LIKE @databasewildcard
    AND sd.[name] NOT IN    (SELECT
                             ed.[database]
                            FROM #excludedatabases ed)

SELECT * FROM #commands

请注意同样的警告适用,我没有使用XP_CMDSHELL,因为我们文件系统的权限非常混乱! 因此,我只是生成了要作为此工作步骤运行的MOVE命令。很遗憾,在我们掌握这个继承环境之前,这是我的环境要求。

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