Sau đây không phải là một giải pháp sao lưu tốt. Trừ khi bạn nghỉ việc và cảm thấy muốn chơi khăm sếp trên đường ra khỏi cửa, bạn không nên sử dụng nó. Nhưng tôi đã học được một vài điều và vui vẻ viết nó, hy vọng những người khác cũng sẽ như vậy. Chúng tôi sẽ sử dụng một số khái niệm ETL có thể thực sự hữu ích trong các trường hợp khác. Các kịch bản đầy đủ ở phía dưới. Đây là những gì chúng ta sẽ làm:
Viết Lược đồ vào bảng riêng
Viết mỗi bảng trong cơ sở dữ liệu vào tệp văn bản có tên động của chính nó
Tạo lại Lược đồ cho DB mới từ tệp văn bản
Tạo lại & Hàng loạt Chèn từng bảng từ tệp văn bản của nó
Trước khi chúng tôi bắt đầu: Để thực hiện toàn bộ DB, bạn sẽ cần vài trăm GB dung lượng lưu trữ. Nếu bạn quá gà, bạn có thể đưa '1000 tập lệnh hàng đầu vào tập lệnh để giới hạn kích thước của các tệp .txt, sau đó bạn sẽ không phải giải thích với sếp về cách bạn điền vào C: \
Kích hoạt xp_cmdshell - giải thích tại đây:
https://blog.sqlauthority.com/2007/04/26/sql-server-enable-xp_cmdshell-USE-sp_ thông minh /
- Viết lược đồ vào một tệp văn bản
Chúng tôi sẽ kiểm tra xem bảng đã tồn tại chưa (Nếu chúng tôi đã chạy tập lệnh trước đó). Mỗi lần thả bàn sẽ dễ dàng hơn.
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
Bây giờ, nếu bạn chọn nhanh * từ HeaderTable, bạn sẽ thấy mọi bảng, mọi cột, kiểu dữ liệu và max_length - mọi thứ chúng ta sẽ cần để tạo lại nó.
- Viết mỗi bảng trong cơ sở dữ liệu vào tệp văn bản có tên động
Đây là nơi nó bắt đầu trở nên mát mẻ. Chúng ta sẽ sử dụng một con trỏ để lặp qua sys.tables và kết xuất từng con vào .txt của riêng nó.
Chúng ta sẽ sử dụng một loạt các biến:
@table đang đi vào con trỏ. Nó sẽ giữ tên của mỗi bảng khi chúng ta đi.
@Database, @filepath, @filename, @filetype đều sẽ được sử dụng để xây dựng một tập hợp các câu lệnh SQL động.
@sql sẽ giữ các lệnh SQL cuối cùng của chúng tôi, để đặt vào sp_executesql.
Mọi thứ có một chút khó khăn với các dấu phân cách và dấu kết thúc hàng. Nếu bạn sử dụng mặc định của | và / r, bạn sẽ có một khoảng thời gian khó khăn thực sự với bảng Nhận xét. Chúng ta sẽ phải sử dụng thứ mà chúng ta biết không được sử dụng ở bất cứ đâu trong cơ sở dữ liệu StackOverflow. Bạn có thể sử dụng newid (), tàu tên lửa và đôi mắt lờ mờ hoặc bạn có thể sử dụng vần điệu yêu thích của bạn. Bất cứ điều gì, miễn là nó không có trên StackOverflow.
Đây là kịch bản:
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
Lưu ý rằng tôi đã đặt sự an toàn trong trường hợp bạn vừa dán nó vào và nhấn F5. Không phải ai cũng sẽ làm điều đó, phải không? exec sp_executesql @sql sẽ không chạy cho đến khi bạn xóa các bình luận viên. Tôi cũng đã bao gồm 10000 đầu.
Đi đến đường dẫn tệp của bạn và bạn sẽ thấy một loạt các tệp văn bản.
Đi trước và mở một lên và thay đổi một số dữ liệu. Nếu bạn nghĩ việc mở chúng theo cách thủ công là dành cho nông dân, bạn có thể sử dụng Fart.exe để tìm và thay thế trong tất cả các tệp văn bản.
- Viết lại tiêu đề
Đi trước và tạo một cơ sở dữ liệu mới.
Chúng tôi sẽ mã hóa giải trí của bảng tiêu đề và sử dụng nó để xây dựng lại phần còn lại.
khôi phục tiêu đề:
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))
Và bây giờ, chúng tôi sẽ chèn hàng loạt Schema của chúng tôi vào 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')
- Tạo lại & hàng loạt Chèn từng bảng từ tệp văn bản của nó
Và đây là nơi mọi thứ trở nên mát mẻ trở lại. Chúng ta sẽ lặp qua HeaderTable và tạo lại mỗi bảng, nối câu lệnh Tạo với STUFF (). Đừng hỏi tôi công cụ () hoạt động như thế nào - một đồng nghiệp cũ (Mike Ignatoski) đã đưa nó cho tôi nhiều năm trước. Các nguồn đáng tin cậy nói rằng ban đầu anh ta đã nhận được nó từ một số người tên là Solomon.
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
Và ở đó bạn có nó - cơ sở dữ liệu của bạn đã được khôi phục từ các tệp văn bản. Bạn có thể ký gửi tệp .bak vào đống rác lịch sử! Miễn là bạn không có bất kỳ chức năng, thủ tục lưu trữ, chế độ xem, ràng buộc hoặc chỉ mục nào.
Dưới đây là các kịch bản đầy đủ: 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
Khôi phục ý tưởng quần jean xấu:
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