web-dev-qa-db-ja.com

データベース全体をテキストファイルにバックアップする方法

それが愚かでそれが機能する場合、それはまだ愚かです。

GDPRについての騒ぎは私に考えさせられました-バックアップに行ってデータを変更/削除する必要がある場合、どのようにそれを行いますか? .bakファイルをクラックして開くのは難しいように思えます。しかし、.txtファイルを開くのは非常に簡単です。

代わりに、データベースをテキストファイルにバックアップして、バックアップから履歴を簡単に削除できるようにできますか?

7
James

これは実際のバックアップには適していませんが、テーブルをテキストファイルにダンプする使用例がいくつかあります。その場合、xp_cmdshellを使用してBCP.EXEを呼び出す別の方法は、を使用することです。 DB_BulkExportSQL# で利用可能なSQLCLRストアドプロシージャ(私が書いた)。次に、File_GZipを使用してファイルを圧縮できます。

以下は、BCP.EXEと比較してDB_BulkExportを使用する利点と欠点です。 :

長所:

  1. xp_cmdshellを有効にする必要はありません
  2. 列ヘッダーを追加します
  3. テキスト修飾は、フィールドなし、すべてのフィールド、またはそれを必要とするフィールドのみ(つまり、非数値/非バイナリフィールド)のいずれかです。テキスト修飾文字列フィールドは、文字の代わりに標準のフィールド区切り文字(コンマやタブなど)と標準の行区切り文字(CRLFやLF/NLなど)を使用できることを意味しますまたは、希望する文字列が文字列フィールドに存在しない場合。テキスト修飾子はユーザー定義(通常は二重引用符)であり、埋め込みテキスト修飾子のエスケープシーケンスは任意のもの(通常は二重引用符でもかまいませんが、バックスラッシュの場合もあります)。
  4. BIT表現の制御:1/0、T/F、またはTrue/False。
  5. (間もなく)SMALLDATETIMEDATETIMEDATETIMEDATETIME2、およびDATETIMEOFFSET形式の制御。

短所:

  1. 無料ではありません(DB_BulkExportおよびFile_GZipはフルバージョンでのみ使用できます)

DB_BulkExportはデータのみをエクスポートすることに注意してください。結果セットの構造は記録されません。これは[〜#〜] bcp [〜#〜]と同じで、メインのコミュニティWikiで提供されているソリューションとまったく同じですそこにあるソリューションは照合、計算列、ほとんどの列オプションなどを無視するので、答えは.

Kin で言及されているSQL Serverの別のオプションは mssql-scripter です。これはフリー/オープンソースのマルチプラットフォームのPythonベースのツールです。使用していませんが、データやスキーマ(テーブル、制約など)を再作成するために実行できるDDLまたはDMLステートメントをエクスポートしているようです。区切られたフィールドとしてではなく、INSERTステートメントとしてのみデータをエクスポートするように見えます。非常に興味深いように見えますが、「 Issues 」を確認して、使用に影響を与えるものがないことを確認してください。


また、この質問(および主要なコミュニティウィキの回答)はSQL Serverについて言及していますが、GDPRを取り巻く問題はSQL Serverに固有のものではありません。したがって、テーブル(およびスキーマなど)をエクスポートする機能は、MySQLに付属している次の2つのユーティリティで利用できることをお伝えしておきます。

PostgreSQLでも、それに付属する次の2つのユーティリティを使用して同じことができます。

Oracleについては、次のリソースを参照してください。完全に同等の出力ではないにしても、少なくとも非常に近くなると思います(正しい方向に向けてくれて Michael Kutz に感謝します)。

同様のユーティリティがDB2に付属しているかどうかはわかりません。

2
Solomon Rutzky

以下は適切なバックアップソリューションではありません。あなたが仕事を辞め、ドアから出て行く途中で上司にいたずらしたいと思わない限り、それを使うべきではありません。しかし、私はいくつかのことを学び、それを書くことを楽しみました。うまくいけば、他の人々もそうなるでしょう。他の状況で実際に役立つ可能性があるいくつかのETL概念を使用します。完全なスクリプトは下部にあります。これから行うのは次のとおりです。

スキーマを独自のテーブルに書き込む
データベース内の各テーブルを、動的に命名された独自のテキストファイルに書き込みます
テキストファイルからスキーマを新しいDBに再作成します
テキストファイルから各テーブルを再作成して一括挿入する

始める前に:DB全体を実行するには、数百GBのストレージが必要です。チキンが多すぎる場合は、スクリプトの「トップ1000」を投げて.txtファイルのサイズを制限することができ、C:\をどのように埋めたかを上司に説明する必要はありません。

Xp_cmdshellを有効にします-ここで説明します:

https://blog.sqlauthority.com/2007/04/26/sql-server-enable-xp_cmdshell-using-sp_configure/

  1. スキーマをテキストファイルに書き込む

テーブルが既に存在するかどうかを確認して確認します(以前にスクリプトを実行したことがある場合)。毎回テーブルをドロップする方が簡単です。

    if exists (select name from sys.tables st with (Nolock) where name = 'HeaderTable')

    begin
    drop table HeaderTable
    end

    SELECT
        st.name, sc.name 'Column_Name', t.Name 'Data_type',sc.max_length 'Max_Length',
        sc.precision, sc.scale, sc.is_nullable
        into HeaderTable
        FROM    
        sys.tables st
        inner join sys.columns sc on sc.object_id = st.object_id
        INNER JOIN sys.types t ON sc.user_type_id = t.user_type_id

ここで、HeaderTableから*をすばやく選択すると、すべてのテーブル、すべての列、そのデータ型、およびmax_lengthが表示されます。これらを再作成するために必要なすべてのものが表示されます。

  1. データベース内の各テーブルを動的に名前が付けられた独自のテキストファイルに書き込む

ここからがクールになります。カーソルを使用してsys.tablesをループし、それぞれを独自の.txtにダンプします。

一連の変数を使用します。

@tableがカーソルに入ります。進行中に各テーブルの名前を保持します。

@ Database、@ filepath、@ filename、@ filetypeはすべて、動的SQLステートメントのセットを構築するために使用されます。

@sqlは最後のSQLコマンドを保持して、sp_executesqlに配置します。

デリミタと行ターミネータを使用すると、物事は少しトリッキーになります。 |のデフォルトを使用する場合/ r、コメントテーブルで本当に苦労するでしょう。 StackOverflowデータベースのどこでも使用されていないことがわかっているものを使用する必要があります。 newid()、ロケット船、ぎこちない目を使用したり、お気に入りの童謡を使用したりできます。 StackOverflowにまだない限り、何でも。

スクリプトは次のとおりです。

    declare @table varchar(255),
    @Database varchar(255),
    @filepath varchar(255),
    @filename varchar(255),
    @filetype varchar(255),
    @sql nvarchar(max),
    @delimiter varchar(255),
    @rowterminator varchar(255)

    set @Database = 'StackOverflow'
    set @filepath = 'C:\Data\' -- fix pretty-print mishandling of not-truly escaped ' 
    set @filetype = '.txt'
    set @delimiter = 'WhimmyWhammyWozzle'
    set @rowterminator = 'WubaLubaDubDub'

    declare c cursor local for

    select name from sys.tables with (Nolock)

    open c

    fetch from c into @table

    while @@FETCH_STATUS = 0
    begin

    SET @filename = @table

    --output to txt
    set @sql = N'declare @bcp varchar(4000)
    set @bcp = ''bcp " select top 10000 * from ' + @table + ' " queryout '
    + @filepath +  @filename + @filetype + ' -t "' + @delimiter + '" -r "'
     + @rowterminator + '" -c -T -d ' + @Database + '''
    print @bcp

    EXECUTE master.dbo.xp_cmdshell @BCP'

    print @sql
    --exec sp_executesql @sql

    fetch next from c into @table
    end

    close c

    deallocate c

貼り付けてF5キーを押した場合に備えて、私は安全装置を取り付けています。誰もがそうすることはないでしょう? exec sp_executesql @sqlは、コメンターを削除するまで実行されません。トップ10000も含めました。

ファイルパスに移動すると、一連のテキストファイルが表示されます。

先に進み、1つを開き、いくつかのデータを変更します。手動で開くことが農民のためであると思われる場合は、Fart.exeを使用して、すべてのテキストファイルを検索して置き換えることができます。

  1. ヘッダーを書き直す

先に進んで、新しいデータベースを作成してください。

ヘッダーテーブルの再作成をハードコーディングし、それを使用して残りを再構築します。

ヘッダーを復元:

    if exists (select name from sys.tables where name = 'HeaderTable')
    begin
    drop table HeaderTable
    end

    create table HeaderTable
    (Table_Name varchar(255),
    Column_Name  varchar(255),
    Data_type  varchar(255),
    Max_Length  varchar(255),
    precision  varchar(255),
    scale varchar(255),
    is_nullable  varchar(255))

次に、HeaderTableにスキーマを一括挿入します。

    set @sql = 'BULK INSERT HeaderTable FROM ''' + @filepath + 'HeaderTable'+ @filetype + ''' WITH (FIELDTERMINATOR = '''
     + @delimiter + ''', ROWTERMINATOR = ''' + @rowterminator + ''')'
    print @sql
    --exec sp_executesql @sql

    We will have to tidy it up a bit, to make the next steps easier:

    update HeaderTable
    set Max_Length = 'max'
    where Max_length = -1

    update HeaderTable
    set Max_Length = '(' + Max_Length + ')'

    update HeaderTable
    set Max_Length = ''
    where Data_type in ( 'int', 'bigint', 'smallint', 'tinyint',
    'date','datetime', 'uniqueidentifier', 'sysname', 'bit')
  1. テキストファイルから各テーブルを再作成して一括挿入する

そして、ここで再び物事がクールになります。 HeaderTableをループして各テーブルを再作成し、CreateステートメントとSTUFF()を連結します。 stuff()がどのように機能するか私に尋ねないでください-古い同僚(Mike Ignatoski)がこれを何年も前に私にくれました。信頼できる情報筋によると、彼はもともとソロモンという名前の男からそれを手に入れました。

    declare @table varchar(255),
    @column_string nvarchar(max),
    @sql nvarchar(max),
    @string nvarchar(max),
    @filepath varchar(255),
    @filename varchar(255),
    @filetype varchar(255),
    @sql nvarchar(max),
    @delimiter varchar(255),
    @rowterminator varchar(255)


    set @filepath = 'C:\Data\' -- fix pretty-print mishandling of not-truly escaped '
    set @filetype = '.txt'
    set @delimiter = 'WhimmyWhammyWozzle'
    set @rowterminator = 'WubaLubaDubDub'

    declare c cursor local for

    select distinct Table_Name from HeaderTable
    where Table_Name != 'HeaderTable'

    open c
    fetch from c into @table

    while @@FETCH_STATUS = 0
    begin

    set @string = null

    set @string = (select stuff( (
    select ', ' + Column_Name + ' ' + Data_type  + Max_Length from HeaderTable
    where Table_Name = @table
    for xml path ('')),1,2,''))

    print @string

    set @sql =  ' if not exists (select top 1 name from sys.tables where name = ''' + @table + ''') begin
    create table ' + @table + ' (' + @string + ') end'

    print @sql
    exec sp_executesql @sql

    --populate the table
    set @sql = 'BULK INSERT ' + @table + ' FROM ''' + @filepath + @table + '.txt'' WITH (FIELDTERMINATOR = '''
    + @delimiter  + ''', ROWTERMINATOR = ''' + @rowterminator + ''' )'

    print @sql
    exec sp_executesql @sql

    fetch next from c into @table

    end

    close c

    deallocate c

これで、データベースがテキストファイルから復元されました。 .bakファイルを歴史のゴミ山に委託することができます!関数、ストアドプロシージャ、ビュー、制約、またはインデックスがない場合。

これが完全なスクリプトです:Bad Idea Jeans Backup:

    declare @table varchar(255),
    @Database varchar(255),
    @filepath varchar(255),
    @filename varchar(255),
    @filetype varchar(255),
    @sql nvarchar(max),
    @delimiter varchar(255),
    @rowterminator varchar(255)

    set @Database = 'StackOverflow'
    set @filepath = 'C:\Data\' -- fix pretty-print mishandling of not-truly escaped '
    set @filetype = '.txt'
    set @delimiter = 'WhimmyWhammyWozzle'
    set @rowterminator = 'WubaLubaDubDub'

    --create database header

    if exists (select name from sys.tables st with (Nolock) where name = 'HeaderTable')

    begin
    drop table HeaderTable
    end

    SELECT
        st.name, sc.name 'Column_Name', t.Name 'Data_type',sc.max_length 'Max_Length',
        sc.precision, sc.scale, sc.is_nullable
        into HeaderTable
        FROM    
        sys.tables st
        inner join sys.columns sc on sc.object_id = st.object_id
        INNER JOIN sys.types t ON sc.user_type_id = t.user_type_id

        select * from HeaderTable

    declare c cursor local for

    select name from sys.tables so with (Nolock)

    open c

    fetch from c into @table

    while @@FETCH_STATUS = 0
    begin

    SET @filename = @table


    --output to txt
    set @sql = N'declare @bcp varchar(4000)
    set @bcp = ''bcp " select top 10000 * from ' + @table + ' " queryout '
    + @filepath +  @filename + @filetype + ' -t "' + @delimiter + '" -r "'
     + @rowterminator + '" -c -T -d ' + @Database + '''
    print @bcp

    EXECUTE master.dbo.xp_cmdshell @BCP'

    print @sql
     exec sp_executesql @sql

    fetch next from c into @table
    end

    close c

    deallocate c

悪い考えのジーンズの復元:

declare @table varchar(255),
    @column_string nvarchar(max),
    @sql nvarchar(max),
    @string nvarchar(max),
    @filepath varchar(255),
    @filename varchar(255),
    @filetype varchar(255),
    @delimiter varchar(255),
    @rowterminator varchar(255)


    set @filepath = 'C:\Data\' -- fix pretty-print mishandling of not-truly escaped '
    set @filetype = '.txt'
    set @delimiter = 'WhimmyWhammyWozzle'
    set @rowterminator = 'WubaLubaDubDub'

    --restore header
    if exists (select name from sys.tables where name = 'HeaderTable')
    begin
    drop table HeaderTable
    end

    create table HeaderTable
    (Table_Name varchar(255),
    Column_Name  varchar(255),
    Data_type  varchar(255),
    Max_Length  varchar(255),
    precision  varchar(255),
    scale varchar(255),
    is_nullable  varchar(255))

    set @sql = 'BULK INSERT HeaderTable FROM ''' + @filepath + 'HeaderTable'+ @filetype + ''' WITH (FIELDTERMINATOR = '''
     + @delimiter + ''', ROWTERMINATOR = ''' + @rowterminator + ''')'
    print @sql
    exec sp_executesql @sql

    --make some changes so that we can concatenate our create tables more easily
    update HeaderTable
    set Max_Length = 'max'
    where Max_length = -1

    update HeaderTable
    set Max_Length = '(' + Max_Length + ')'

    update HeaderTable
    set Max_Length = ''
    where Data_type in ( 'int', 'bigint', 'smallint', 'tinyint',
    'date','datetime', 'uniqueidentifier', 'sysname', 'bit')

    select * from HeaderTable

    --restore DB

    declare c cursor local for

    select distinct name from sys.columns
    where name != 'HeaderTable'

    open c
    fetch from c into @table

    while @@FETCH_STATUS = 0
    begin

    set @string = null

    set @string = (select stuff( (
    select ', ' + Column_Name + ' ' + Data_type  + Max_Length from HeaderTable
    where name = @table
    for xml path ('')),1,2,''))

    print @string

    set @sql =  ' if not exists (select top 1 name from sys.tables where name = ''' + @table + ''') begin
    create table ' + @table + ' (' + @string + ') end'

    print @sql
    --exec sp_executesql @sql

    set @sql = 'BULK INSERT ' + @table + ' FROM ' + '' + @filepath + @table + '.txt'' WITH (FIELDTERMINATOR = '''
    + @delimiter  + ''', ROWTERMINATOR = ''' + @rowterminator + ''' )'

    print @sql
    --exec sp_executesql @sql

    fetch next from c into @table

    end

    close c

    deallocate c
4
Brent Ozar