12

サーバー上に(別の名前で)新しいデータベースをコピーして作成したいSQLServer2008データベースがあります。私はデータの維持には関心がありません。新しいデータベースは、初心者向けのデータなしで作成できます。私が探しているのは次のとおりです。

  • 古いデータベースの構造を維持しながら、新しいデータベースを作成します
  • 新しいデータベースの名前を設定します
  • すべてのvarcharおよびcharデータ型をnvarcharおよびncharに変更します
  • すべてのテキストデータ型をnvarchar(MAX)に変更します

余談ですが、私のタスクの一部ではないが、次のことを検討したい2つの質問があります。

  • SQLServerデータベースをSQLServer2012にアップグレードするにはどうすればよいですか。
  • データベースを簡単にアップグレードできるようにするために、データベースに対して実行する必要のある準備作業はありますか?
4

2 に答える 2

31

これは実際には複数の質問の組み合わせです。


質問 1 と 2

  • 古いデータベースの構造を維持する新しいデータベースを作成する
  • 新しいデータベースの名前を設定します

最も単純なバックアップ コマンドは次のとおりです。

BACKUP DATABASE dbname TO DISK = 'C:\some folder\dbname.bak' WITH INIT;
-- or WITH INIT, COMPRESSION if you are on Enterprise or Developer

これを別のデータベースとして復元するには、同じファイルを同じ場所に配置しようとするため、ファイル名を知る必要があります。したがって、次を実行すると:

EXEC dbname.dbo.sp_helpfile;

データ ファイルとログ ファイルの名前とパスを含む出力が表示されます。復元を構築するときは、これらを使用する必要がありますが、パスを新しいデータベースの名前に置き換えます。たとえば、次のようになります。

RESTORE DATABASE newname FROM DISK = 'C:\some folder\dbname.bak'
  WITH MOVE 'dbname' TO 'C:\path_from_sp_helpfile_output\newname_data.mdf',
  MOVE 'dbname_log' TO 'C:\path_from_sp_helpfile_output\newname_log.ldf';

dbnameandnewnameを実際のデータベース名に置き換え、さらにC:\some folderandC:\path_from_sp_helpfile_output\を実際のパスに置き換える必要があります。それらが何であるかを知らない限り、私の答えをより具体的にすることはできません。


完全な再現は次のとおりです。

CREATE DATABASE [DB-A];
GO

EXEC [DB-A].dbo.sp_helpfile;

部分的な結果:

name     fileid filename
-------- ------ ---------------------------------
DB-A     1      C:\Program Files\...\DB-A.mdf
DB-A_log 2      C:\Program Files\...\DB-A_log.ldf

次に、バックアップを実行します。

BACKUP DATABASE [DB-A] TO DISK = 'C:\dev\DB-A.bak' WITH INIT;

もちろん、クローン ターゲット (この場合はDB-B) が既に存在する場合は、それを削除する必要があります。

USE [master];
GO
IF DB_ID('DB-B') IS NOT NULL
BEGIN
  ALTER DATABASE [DB-B] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
  DROP DATABASE [DB-B];
END
GO

これで、この復元が正常に実行され、DB-B という名前に変更された DB-A のコピーが作成されます。

RESTORE DATABASE [DB-B] FROM DISK = 'C:\dev\DB-A.bak'
  WITH MOVE 'DB-A'     TO 'C:\Program Files\...\DB-B.mdf',
       MOVE 'DB-A_log' TO 'C:\Program Files\...\DB-B_log.ldf';

質問 3 と 4

  • すべての varchar および char データ型を nvarchar および nchar に変更します
  • すべてのテキスト データ型を nvarchar(MAX) に変更します

特にこれらの列の一部が制約に参加している場合、リファクタリングは大きな苦痛です。この方法で非常に基本的なスクリプトを作成できますが、これらすべての変数を処理するには、より高度な機能が必要になります。これは、すべての列が null 可能であり、制約に参加していないことを前提としています。

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += '
  ALTER TABLE ' + 
  QUOTENAME(OBJECT_SCHEMA_NAME(c.[object_id])) 
  + '.' + QUOTENAME(OBJECT_NAME(c.[object_id]))
  + ' ALTER COLUMN ' + QUOTENAME(c.name) + ' '
  + CASE t.name WHEN N'text' 
     THEN N'nvarchar(max)' 
     ELSE N'n' + t.name + '(' + RTRIM(c.max_length) + ')'
  END + ';'
FROM sys.columns AS c
INNER JOIN sys.types AS t
ON c.user_type_id = t.user_type_id
WHERE c.system_type_id IN (35, 167, 175)
AND OBJECTPROPERTY(c.[object_id], 'IsMsShipped') = 0;

PRINT @sql;
-- EXEC sp_executesql @sql;

PRINT 出力を使用して、スクリプトの最初の 8K を確認し、問題がないと思われる場合は、EXEC.

完了したら、すべてのインデックスを再構築する必要があります。

とはいえ、Tony が提案したようにデータベースをスクリプト化する (または空のデータベースに対してRed Gate の SQL Compare のようなツールまたはその多くの代替手段の 1 つを使用する) ことは、特にこれらの列の一部が制約に参加している場合、おそらくはるかに簡単になります。タイプを変更するには、削除して再作成する必要がある場合があります。


質問 5 と 6

  • SQL Server データベースを SQL Server 2012 にアップグレードするにはどうすればよいですか
  • データベースを簡単にアップグレードできるようにするために、データベースで実行する必要がある準備作業はありますか?

2008 インスタンスで 1 つのデータベースだけをアップグレードすることはできません。その場でアップグレードするか、新しいインスタンスをセットアップして (Tony が説明したように)、データベースを移行します (できればバックアップ/復元を使用します。多くの人はデタッチ/アタッチするように指示しますが、それははるかに安全ではありません)。実行する必要がある準備作業には、次のものが含まれます。

アップグレード後は、次のことを行います。

  • 互換性レベルを 110 に設定します
  • すべての統計を更新する
于 2012-09-18T23:36:30.910 に答える
2

データベースをコピーするスクリプトのソース。

USE master;

DECLARE
    @SourceDatabaseName AS SYSNAME = '<SourceDB>', 
    @TargetDatabaseName AS SYSNAME = '<TargetDB>'



-- ============================================
-- Define path where backup will be saved
-- ============================================
IF NOT EXISTS (SELECT 1 FROM sys.databases WHERE name = @SourceDatabaseName)
    RAISERROR ('Variable @SourceDatabaseName is not set correctly !', 20, 1) WITH LOG       

DECLARE @SourceBackupFilePath varchar(2000)
SELECT @SourceBackupFilePath = BMF.physical_device_name
FROM
    msdb.dbo.backupset B
    JOIN msdb.dbo.backupmediafamily BMF ON B.media_set_id = BMF.media_set_id
WHERE B.database_name = @SourceDatabaseName
ORDER BY B.backup_finish_date DESC

SET @SourceBackupFilePath = REPLACE(@SourceBackupFilePath, '.bak', '_clone.bak')

IF @SourceBackupFilePath IS NULL
        RAISERROR ('Could not determine file path for backup file!', 16, 1) WITH LOG



-- ============================================
-- Backup source database
-- ============================================
DECLARE @Sql NVARCHAR(MAX) 
SET @Sql = 'BACKUP DATABASE @SourceDatabaseName TO DISK = ''@SourceBackupFilePath'''
SET @Sql = REPLACE(@Sql, '@SourceDatabaseName', @SourceDatabaseName)
SET @Sql = REPLACE(@Sql, '@SourceBackupFilePath', @SourceBackupFilePath)
SELECT 'Performing backup...', @Sql as ExecutedSql
EXEC (@Sql)



-- ============================================
-- Automatically compose database files (.mdf and .ldf) paths
-- ============================================
DECLARE
          @LogicalDataFileName as NVARCHAR(MAX)
        , @LogicalLogFileName as NVARCHAR(MAX)
        , @TargetDataFilePath as NVARCHAR(MAX)
        , @TargetLogFilePath as NVARCHAR(MAX)

SELECT
        @LogicalDataFileName = name,
        @TargetDataFilePath = SUBSTRING(physical_name,1,LEN(physical_name)-CHARINDEX('\',REVERSE(physical_name))) + '\' + @TargetDatabaseName + '.mdf'
FROM sys.master_files
WHERE
        database_id = DB_ID(@SourceDatabaseName)        
        AND type = 0            -- datafile file

SELECT
        @LogicalLogFileName = name,
        @TargetLogFilePath = SUBSTRING(physical_name,1,LEN(physical_name)-CHARINDEX('\',REVERSE(physical_name))) + '\' + @TargetDatabaseName + '.ldf'
FROM sys.master_files
WHERE
        database_id = DB_ID(@SourceDatabaseName)        
        AND type = 1            -- log file     

SELECT  
    @LogicalDataFileName as LogicalDataFileName,
    @LogicalLogFileName as LogicalLogFileName,
    @TargetDataFilePath as TargetDataFilePath,
    @TargetLogFilePath as TargetLogFilePath                

IF @TargetDataFilePath IS NULL OR @TargetLogFilePath IS NULL
    RAISERROR ('Could not determine target paths!', 16, 1) WITH LOG



-- ============================================
-- Restore target database
-- ============================================
IF EXISTS (SELECT 1 FROM sys.databases WHERE name = @TargetDatabaseName)
    RAISERROR ('A database with the same name already exists!', 20, 1) WITH LOG        

SET @Sql = 'RESTORE DATABASE @TargetDatabaseName
FROM DISK = ''@SourceBackupFilePath'' 
WITH MOVE ''@LogicalDataFileName'' TO ''@TargetDataFilePath'',
MOVE ''@LogicalLogFileName'' TO ''@TargetLogFilePath''' 
SET @Sql = REPLACE(@Sql, '@TargetDatabaseName', @TargetDatabaseName)
SET @Sql = REPLACE(@Sql, '@SourceBackupFilePath', @SourceBackupFilePath)
SET @Sql = REPLACE(@Sql, '@LogicalDataFileName', @LogicalDataFileName)
SET @Sql = REPLACE(@Sql, '@TargetDataFilePath', @TargetDataFilePath)
SET @Sql = REPLACE(@Sql, '@LogicalLogFileName', @LogicalLogFileName)
SET @Sql = REPLACE(@Sql, '@TargetLogFilePath', @TargetLogFilePath)
SELECT 'Restoring...', @Sql as ExecutedSql
EXEC (@Sql)
于 2014-02-20T06:35:02.217 に答える