Das Folgende ist keine gute Backup-Lösung. Wenn Sie Ihren Job nicht kündigen und Ihrem Chef auf dem Weg zur Tür einen Streich spielen möchten, sollten Sie ihn nicht benutzen. Aber ich habe ein paar Dinge gelernt und hatte Spaß beim Schreiben, hoffentlich auch bei anderen. Wir werden einige ETL-Konzepte verwenden, die unter anderen Umständen tatsächlich nützlich sein könnten. Die vollständigen Skripte finden Sie unten. Folgendes werden wir tun:
Schreiben Sie das Schema in eine eigene Tabelle.
Schreiben Sie jede Tabelle in der Datenbank in eine eigene dynamisch benannte Textdatei.
Erstellen Sie das Schema in einer neuen Datenbank aus der Textdatei
neu. Erstellen Sie eine neue Tabelle und fügen Sie jede Tabelle aus ihrer Textdatei ein
Bevor wir beginnen: Um die gesamte Datenbank zu erstellen, benötigen Sie mehrere hundert GB Speicher. Wenn Sie zu pingelig sind, können Sie die Top 1000 im Skript eingeben, um die Größe der TXT-Dateien zu begrenzen. Dann müssen Sie Ihrem Chef nicht erklären, wie Sie C: \ ausgefüllt haben
Aktivieren Sie xp_cmdshell - hier erklärt:
https://blog.sqlauthority.com/2007/04/26/sql-server-enable-xp_cmdshell-using-sp_configure/
- Schreiben Sie das Schema in eine Textdatei
Wir werden prüfen, ob die Tabelle bereits vorhanden ist (wenn wir das Skript bereits ausgeführt haben). Es ist einfacher, den Tisch jedes Mal einfach fallen zu lassen.
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
Wenn Sie jetzt eine schnelle Auswahl * aus HeaderTable vornehmen, sehen Sie jede Tabelle, jede Spalte, ihren Datentyp und ihre maximale Länge - alles, was wir zum erneuten Erstellen benötigen.
- Schreiben Sie jede Tabelle in der Datenbank in eine eigene dynamisch benannte Textdatei
Hier fängt es an, cool zu werden. Wir werden einen Cursor verwenden, um sys.tables zu durchlaufen und jeden in seine eigene .txt zu kopieren.
Wir werden eine Reihe von Variablen verwenden:
@table geht in den Cursor. Es wird die Namen jeder Tabelle enthalten, während wir gehen.
@Database, @filepath, @filename, @filetype werden alle zum Erstellen einer Reihe dynamischer SQL-Anweisungen verwendet.
@sql wird unsere letzten SQL-Befehle enthalten, um sie in sp_executesql zu setzen.
Mit den Trennzeichen und Zeilenabschlusszeichen wird es etwas schwierig. Wenn Sie die Standardeinstellungen von | verwenden und / r, Sie werden es mit der Kommentartabelle wirklich schwer haben. Wir müssen etwas verwenden, von dem wir wissen, dass es nirgendwo in der StackOverflow-Datenbank verwendet wird. Sie könnten newid (), Raketenschiffe und Kulleraugen verwenden oder Sie könnten Ihren Lieblingskinderreim verwenden. Alles, solange es noch nicht auf StackOverflow ist.
Hier ist das Skript:
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
Beachten Sie, dass ich die Sicherheit aktiviert habe, falls Sie sie gerade eingefügt und F5 gedrückt haben. Nicht, dass das jemals jemand tun würde, oder? exec sp_executesql @sql wird erst ausgeführt, wenn Sie die Kommentatoren entfernen. Ich habe auch eine Top 10000 aufgenommen.
Gehen Sie zu Ihrem Dateipfad, und Sie sollten eine Reihe von Textdateien sehen.
Öffnen Sie eine und ändern Sie einige Daten. Wenn Sie der Meinung sind, dass das manuelle Öffnen für Bauern bestimmt ist, können Sie mit Fart.exe alle Textdateien suchen und ersetzen.
- Schreiben Sie den Header neu
Erstellen Sie eine neue Datenbank.
Wir werden die Neuerstellung der Header-Tabelle hart codieren und sie verwenden, um den Rest neu zu erstellen.
Header wiederherstellen:
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))
Und jetzt werden wir unser Schema in Massen in HeaderTable einfügen:
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')
- Neu erstellen & Bulk Fügen Sie jede Tabelle aus ihrer Textdatei ein
Und hier wird es wieder cool. Wir werden HeaderTable durchlaufen und jede Tabelle neu erstellen, wobei die Create-Anweisung mit STUFF () verkettet wird. Fragen Sie mich nicht, wie stuff () funktioniert - ein alter Mitarbeiter (Mike Ignatoski) hat mir das vor Jahren gegeben. Zuverlässige Quellen sagen, er habe es ursprünglich von einem Typen namens Solomon bekommen.
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
Und da haben Sie es - Ihre Datenbank wurde aus Textdateien wiederhergestellt. Sie können die .bak-Datei auf den Müllhaufen der Geschichte legen! Solange Sie keine Funktionen, gespeicherten Prozeduren, Ansichten, Einschränkungen oder Indizes haben.
Hier sind die vollständigen Skripte: 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
Bad Idea Jeans Restore:
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