How to attach a mdf file bypassing filestream information? - sql-server

I have a mdf and ldf files from a database that in principle have filestream data too.
Since i need to debug an issue related only to the relational tables and the filestream folder is too big I wonder whether there is a way to attach a db only from mdf and ldf and somehow skipping filestream
This is a typical attach query taken from this question:
USE [master]
GO
CREATE DATABASE [AdventureWorks2008] ON
( FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10.SQLTRAININGKIT\MSSQL\DATA\AdventureWorks2008_Data.mdf' ),
( FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10.SQLTRAININGKIT\MSSQL\DATA\AdventureWorks2008_Log.ldf' ),
FILEGROUP [PRIMARY] CONTAINS FILESTREAM DEFAULT
( NAME = N'Documents', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10.SQLTRAININGKIT\MSSQL\DATA\Documents' )
FOR ATTACH
GO
Since i do not have the filestream data how can i do?

As far as I know there is no way to do this with attaching (since attach requires all files to be present). Also look at this answer.
There is alternative though. If your database is in full recovery mode you can take partial backup without filestream group. You can then restore from that backup and any missing filegroup will be in offline mode and inaccessible. Any query that will try to use objects from missing filegroup will fail.
Sample commands:
BACKUP DATABASE [Demo]
FILEGROUP = N'PRIMARY'
TO DISK = N'.\MSSQL\Backup\Demo.bak'
WITH COPY_ONLY, NOFORMAT, NOINIT, NAME = N'Demo-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
RESTORE DATABASE [OtherDatabase]
FILE = N'Demo' FROM DISK = N'.\MSSQL\Backup\Demo.bak' WITH FILE = 1,
MOVE N'Demo' TO N'.\MSSQL\DATA\OtherDatabase.mdf',
MOVE N'Demo_log' TO N'.\MSSQL\DATA\OtherDatabase_Log.ldf',
MOVE N'FStream' TO N'.\MSSQL\DATA\OtherDatabase_Documents', NOUNLOAD, STATS = 10
GO
EDIT:
Some additional helpful links regarding backing and restoring files/filegroups:
https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/back-up-files-and-filegroups-sql-server
https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/restore-files-and-filegroups-sql-server
EDIT 2:
If your database is in simple recovery mode and you want to take backup of only specific filegroups, you have to make all other filegroups readonly. Then you can use READ_WRITE_FILEGROUPS to backup only R/W filegroups.
Sample commands:
USE [master]
GO
ALTER DATABASE [Demo] MODIFY FILEGROUP [FilestreamGroup] READONLY
GO
BACKUP DATABASE [Demo] READ_WRITE_FILEGROUPS TO DISK = N'.\MSSQL\Backup\EFCoreDemo.bak'
WITH COPY_ONLY, NOFORMAT, NOINIT, NAME = N'Demo-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
ALTER DATABASE [Demo] MODIFY FILEGROUP [FilestreamGroup] READ_WRITE
GO
RESTORE DATABASE [OtherDatabase]
FILE = N'Demo' FROM DISK = N'.\MSSQL\Backup\EFCoreDemo.bak' WITH FILE = 1,
MOVE N'Demo' TO N'.\MSSQL\DATA\OtherDatabase.mdf',
MOVE N'Demo_log' TO N'.\MSSQL\DATA\OtherDatabase_Log.ldf',
MOVE N'FStream' TO N'.\MSSQL\DATA\OtherDatabase_Documents', NOUNLOAD, STATS = 10
GO

Related

Transaction Log Backup fails with "Exclusive access could not be obtained because the database is in use"

I am attempting a Log Shipping failover test and the step which is intended to put the database into restoring mode is failing with the error "Exclusive access could not be obtained because the database is in use".
The action was carried out through SSMS selecting "Transaction Log" and also selecting "backup the tail of the log" under Media Options which should leave the database in "restoring mode".
After the failure I attempted to put the database into single user mode first and also take it offline but both commands didn't work (or fail).
I have repeated the action against a test database and that worked with no problem. The T-SQL is below:
BACKUP LOG [TESTDB] TO DISK = N'U:\MSSQL\Backup\TESTDB.bak' WITH NO_TRUNCATE , NOFORMAT, NOINIT, NAME = N'TESTDB-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, NORECOVERY , STATS = 10, CHECKSUM
GO
declare #backupSetId as int
select #backupSetId = position from msdb..backupset where database_name=N'TESTDB' and backup_set_id=(select max(backup_set_id) from msdb..backupset where database_name=N'TESTDB' )
if #backupSetId is null begin raiserror(N'Verify failed. Backup information for database ''TESTDB'' not found.', 16, 1) end
RESTORE VERIFYONLY FROM DISK = N'U:\MSSQL\Backup\TESTDB.bak' WITH FILE = #backupSetId, NOUNLOAD, NOREWIND
GO
I also checked for any blocking or running transactions but nothing showed up.
Any ideas anyone?
A log backup that leaves the target database in RESTORING is called a "Tail Log Backup". And taking the database offline requires terminating all other connections to the database. Like this:
use testdb
go
alter database testdb set single_user with rollback immediate
go
use master
BACKUP LOG [TESTDB] TO DISK = N'c:\temp\TESTDB.bak' WITH NO_TRUNCATE , NOFORMAT, NOINIT, NAME = N'TESTDB-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, NORECOVERY , STATS = 10, CHECKSUM
GO

SQL Server - backup of PRIMARY filegroup + the Log file

I have tried backing up my primary filegroup (have 3 other filegroups i dont need to restore) and the log file using:
BACKUP DATABASE [dblive]
FILEGROUP = N'PRIMARY',
TO DISK = N'C:\SQL_Backups\test2_primary.bak'
WITH NOFORMAT, NOINIT,
NAME = N'dblive-Full Filegroup Backup',
SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
BACKUP LOG [dblive] TO DISK = N'C:\SQL_Backups\test2_log.bak'
WITH NOFORMAT, NOINIT,
NAME = N'dblive-Transaction Log Database Backup',
SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
i zip up the files from the customer site (db in full recovery mode) and restore inhouse.
when i run the restore:
RESTORE DATABASE [CustomerDB]
FROM DISK = N'C:\backups\CustomerDB\test2_primary.bak'
WITH recovery,
MOVE N'AwardsBA_DB' TO N'C:\Databases\CustomerDB\CustomerDB.mdf',
MOVE N'AwardsBA_DB_log' TO N'C:\Databases\CustomerDB\CustomerDB.ldf',
NOUNLOAD, REPLACE, STATS = 10
RESTORE LOG CustomerDB FROM DISK = 'C:\backups\CustomerDB\test2_log.bak'
WITH RECOVERY;
i get this error message
"This log cannot be restored because a gap in the log chain was
created"
Any ideas on how i can backup this Primary filegroup and Log and restore them inhouse?
You won't be able to restore that log so you have to create a new one.
RESTORE DATABASE [CustomerDB]
FROM DISK = N'C:\backups\CustomerDB\test2_primary.bak'
WITH recovery,
MOVE N'AwardsBA_DB' TO N'C:\Databases\CustomerDB\CustomerDB.mdf',
MOVE N'AwardsBA_DB_log' TO N'C:\Databases\CustomerDB\CustomerDB.ldf',
NOUNLOAD, REPLACE, STATS = 10
ALTER DATABASE [CustomerDB] SET EMERGENCY, SINGLE_USER
ALTER DATABASE [CustomerDB] REBUILD LOG ON (NAME= AwardsBA_DB_log, FILENAME='C:\Databases\CustomerDB\CustomerDB_1.ldf')
ALTER DATABASE CNBILL SET ONLINE, MULTI_USER

partitioned Database Restore issue

I am having a issue for restoring a partitioned database using the below script.
I have 7 partitions in the database.
here is the code .
declare #Sql varchar(max)
SET #Sql = 'RESTORE DATABASE [NEWS]
FILE = ''DEMO'',
FILEGROUP = ''DEMO''
FROM DISK = ''C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\DEMO_clone.bak
WITH FILE = 1, NOUNLOAD, REPLACE, STATS = 10
GO
RESTORE LOG [NEWS]
FROM DISK = ''C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\DEMO_clone.bak''
WITH RECOVERY
GO'''
EXEC (#Sql)
Its showing the error as incorrect syntax near '\'.
Anyone knows what is the issue is ?
GO is not a T-SQL command so you can't include it in a dynamic SQL script. GO is a batch separator interpreted by SQL Server client tools.
There is no need for the GO batch separators or dynamic SQL in here so I'm guessing the SQL in your question is actually built dynamically. There are also some other errors like misplaced quotes in your code. Below is the corrected version. I think you may need to add NORECOVERY to the RESTORE DATABASE too:
SET #Sql = 'RESTORE DATABASE [NEWS]
FILE = ''DEMO'',
FILEGROUP = ''DEMO''
FROM DISK = ''C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\DEMO_clone.bak''
WITH FILE = 1, NOUNLOAD, REPLACE, STATS = 10;
RESTORE LOG [NEWS]
FROM DISK = ''C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\DEMO_clone.bak'';
';

How to restore a SQL Server backup to another database?

I want to restore a database to 12/29/2016. I want to restore to another name so I do not lose the state of the original database. The name of my database is APDatabase.
How do I modify the SQL below to restore to a database called TempAPDatabase? I also want to be careful not to lose any of the backup information which is stored on the disk as 87A991B1-9305-45C1-A461-9B1A3174A707.
USE [master]
BACKUP LOG [APDatabase]
TO DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MYSQLSERVER\MSSQL\Backup\APDatabase_LogBackup_2017-03-13_10-52-54.bak'
WITH NOFORMAT, NOINIT,
NAME = N'APDatabase_LogBackup_2017-03-13_10-52-54',
NOSKIP, NOREWIND, NOUNLOAD, NORECOVERY, STATS = 5
RESTORE DATABASE [APDatabase]
FROM DISK = N'{87A991B1-9305-45C1-A461-9B1A3174A707}10'
WITH FILE = 1, NORECOVERY, NOUNLOAD, STATS = 5
RESTORE LOG [APDatabase]
FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MYSQLSERVER\MSSQL\Backup\APDatabase_LogBackup_2017-03-10_06-47-10.bak'
WITH FILE = 1, NOUNLOAD, STATS = 5, STOPAT = N'2016-12-29T00:00:00'
GO
Assuming the rest of your command is correct, you just need to state the new name as the database you're restoring.
RESTORE DATABASE [TempAPDatabase]
FROM DISK = N'{87A991B1-9305-45C1-A461-9B1A3174A707}10'
WITH FILE = 1, NORECOVERY, NOUNLOAD, STATS = 5
RESTORE LOG [TempAPDatabase]
FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MYSQLSERVER\MSSQL\Backup\APDatabase_LogBackup_2017-03-10_06-47-10.bak'
WITH FILE = 1, NOUNLOAD, STATS = 5, STOPAT = N'2016-12-29T00:00:00'
GO

Restore SQL Database with Replace option

I am trying to understand the REPLACE option from various sources and have not clarified myself. I am using SQL Server 2014 version.
What is the difference between below 2 queries? Both are completing without any error. With and Without Replace.
USE [master]
RESTORE DATABASE [Test] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\MyDatabase.bak'
WITH FILE = 3, NOUNLOAD, STATS = 5
GO
Vs
USE [master]
RESTORE DATABASE [Test] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\MyDatabase.bak'
WITH REPLACE, FILE = 3, NOUNLOAD, STATS = 5
GO
When I try to Replace with the .mdf and .ldf of an existing database (Test2), I get an error. My understanding so far is that I can restore the backup of [Test1] db with the name [Test2] (This already exists in my server and Test1 DB also exists).
I got the statement for REPLACE "Restoring over an existing database with a backup taken of another database." from one of Microsoft Link.
USE [master]
RESTORE DATABASE [Test2] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\Backup\MyDatabase.bak'
WITH REPLACE, FILE = 3, NOUNLOAD, STATS = 5
GO
Error:
Msg 1834, Level 16, State 1, Line 2
The file 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\test1.mdf' cannot be overwritten. It is being used by database 'test1'.
Msg 3156, Level 16, State 4, Line 2
'test1' cannot be restored to 'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\test1.mdf'. Use WITH MOVE to identify a valid location for the file.
Msg 1834, Level 16, State 1, Line 2
What is the purpose of the REPLACE option and what it replaces behind the scene. Can any one please explain with any example?
The purpose of the REPLACE option is to allow you to overwrite a database name (clobber an existing database with a different name from the backup). Your errors are caused by you trying to overwrite the files of another database from the one you asked to restore over. So restoring over Test2 database but clobbering Test1 database files (Test1.MDB and Test1.LDB). If you don't use the MOVE clause then the RESTORE command will use the same filenames as the BACKUP. Probably not a good idea otherwise things are going to get pretty confusing. (Test2 database pointing to Test1.mdb and Test1.ldb)
My script below demonstrates the issue.
I create database Test1.
I Back it up.
I try to restore it to Test2 using REPLACE. It fails, because Test1.mdb and Test1.ldb are being used by the Test1 database.
I drop the Test1 database.
I try to restore it to Test2 using REPLACE and it now works. (But is using Test1.mdb and Test1.ldb).
CREATE DATABASE [Test1]
ON PRIMARY
( NAME = N'Test1', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\Test1.mdf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
LOG ON
( NAME = N'Test1_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\Test1_log.ldf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
GO
BACKUP DATABASE [Test1] TO DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\Test1.bak' WITH COPY_ONLY, NOFORMAT, NOINIT, NAME = N'Test1-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
--Fails... It is being used by database 'Test1'.
RESTORE DATABASE [Test2] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\Test1.bak'
WITH REPLACE, NOUNLOAD, STATS = 5
GO
DROP DATABASE Test1
GO
--Now works, but the files are Test1.mdf and Test1.ldf
RESTORE DATABASE [Test2] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\Test1.bak'
WITH REPLACE, NOUNLOAD, STATS = 5
GO
DROP DATABASE Test2
GO
CREATE DATABASE [Test2]
ON PRIMARY
( NAME = N'Test1', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\Test2.mdf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
LOG ON
( NAME = N'Test1_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\Test2_log.ldf' , SIZE = 8192KB , FILEGROWTH = 65536KB )
GO
--Now the same command works, because Test1.mdf and Test1.ldf are not in use.
RESTORE DATABASE [Test2] FROM DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\Test1.bak'
WITH REPLACE, NOUNLOAD, STATS = 5
GO
This is Microsoft's explanation of the REPLACE option:
https://learn.microsoft.com/en-us/sql/t-sql/statements/restore-statements-transact-sql?view=sql-server-2017#REPLACEoption
REPLACE Option Impact
REPLACE should be used rarely and only after careful consideration. Restore normally prevents accidentally overwriting a database with a different database. If the database specified in a RESTORE statement already exists on the current server and the specified database family GUID differs from the database family GUID recorded in the backup set, the database is not restored. This is an important safeguard.
The REPLACE option overrides several important safety checks that restore normally performs. The overridden checks are as follows:
Restoring over an existing database with a backup taken of another database.
With the REPLACE option, restore allows you to overwrite an existing database with whatever database is in the backup set, even if the specified database name differs from the database name recorded in the backup set. This can result in accidentally overwriting a database by a different database.
Restoring over a database using the full or bulk-logged recovery model where a tail-log backup has not been taken and the STOPAT option is not used.
With the REPLACE option, you can lose committed work, because the log written most recently has not been backed up.
Overwriting existing files.
For example, a mistake could allow overwriting files of the wrong type, such as .xls files, or that are being used by another database that is not online. Arbitrary data loss is possible if existing files are overwritten, although the restored database is complete.
The way I found is like following:
Bring your database offline -> tasks-> bring it offline
Go to your Database in the Windows Explorer and delete your mdf and log.ldf
C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\Test1.mdf
Let your Sql script run
That's it.
In general I think it is better to create a backup and restore this. In the database.
right click on database -> Tasks -> Take Offline
right click on database -> Tasks -> Restore -> Database
Select a Page -> General -> chose your file under device
Select a Page -> Options -> mark Overwrite the existing database (with replace)
Let it run

Resources