SQL Server Management Studio - trouble restoring from bak and trn - sql-server

I am trying to restore a database from .bak and trn files. I am not able to see .bak and .trn files through the SQL Server Management Studio. But when I go to the folder I see them. I used T-sql but it says access is denied. I am a sysadmin on the server. Can someone please help me with it.
Script:
RESTORE DATABASE [XYZ]
FROM DISK = N'R:\MSSQL10_50.MSSQLSERVER\MSSQL\Restore\XYZ_Full.bak' WITH FILE = 1
GO
Error: Msg 3201, Level 16, State 2, Line 3
Cannot open backup device 'R:..."Operating system error 5(Access is denied.).

Make sure your account (windows or sql server) in SSMS has the right to backup/restore, sysadmin, db_backoperator, etc.
The backup and restore processes runs under the SQL Server (Engine) Service account since you might be running SSMS on your laptop but working with files on the server.
It doesn't matter who you are logged in as, it is the service account that needs access to the directory and files.
Is the service account a domain account or a local service? I use a domain account so that I can work with files on a UNC path.
Also, there are two system stored procedures that get executed during the browse dialog: master.dbo.xp_dirtree, master.dbo.xp_fileexist.
If they return empty results from a query window, it is a permission issue with the SQL Server Service account.
Profiler Trace Browse operation (Adventure Works).
declare #Path nvarchar(255)
declare #Name nvarchar(255)
select #Path = N'C:\mssql\save me\backup\AdventureWorks2012'
select #Name = N'AdventureWorks2012_backup_2012_11_30_160723_2147507.bak'
create table #filetmpfin (Name nvarchar(255) NOT NULL, IsFile bit NULL)
if(#Name is null)
begin
create table #filetmp (Name nvarchar(255) NOT NULL, depth int NOT NULL, IsFile bit NULL )
insert #filetmp EXECUTE master.dbo.xp_dirtree #Path, 1, 1
insert #filetmpfin select Name, IsFile from #filetmp f
drop table #filetmp
end
if(NOT #Name is null)
begin
declare #FullName nvarchar(300)
if(#Path is null)
select #FullName = #Name
else
select #FullName = #Path + '\' + #Name
create table #filetmp2 ( Exist bit NOT NULL, IsDir bit NOT NULL, DirExist bit NULL )
insert #filetmp2 EXECUTE master.dbo.xp_fileexist #FullName
insert #filetmpfin select #Name, 1-IsDir from #filetmp2 where Exist = 1 or IsDir = 1
drop table #filetmp2
end
SELECT
Name AS [Name],
IsFile AS [IsFile]
FROM
#filetmpfin
ORDER BY
[IsFile] ASC,[Name] ASC
drop table #filetmpfin

Related

Restore master database into newly named database with .bak file

I wrote a script to restore to a new database that already has populated tables (basically the master database contains the same tables as the school database but one table needs renaming as it was renamed incorrectly in master). The .bak file was from the master database, and i'm trying to restore it to the new database, however I'm getting an error.
(2 rows affected)
-------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------
master mastlog
(1 row affected)
C:\Program Files\Microsoft SQL Server\MSSQL13.SQLEXPRESS\MSSQL\DATA
C:\Program Files\Microsoft SQL Server\MSSQL13.SQLEXPRESS\MSSQL\DATA
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C:\Program Files\Microsoft SQL Server\MSSQL13.SQLEXPRESS\MSSQL\DATA
(1 row affected)
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C:\Program Files\Microsoft SQL Server\MSSQL13.SQLEXPRESS\MSSQL\DATA
(1 row affected)
Msg 3176, Level 16, State 1, Line 59
File '' is claimed by 'mastlog'(2) and 'master'(1). The WITH MOVE clause can be used to relocate one or more files.
Msg 3013, Level 16, State 1, Line 59
RESTORE DATABASE is terminating abnormally.
And this is the script:
use school;
DECLARE #TableSchema sys.sysname = N'dbo'
DECLARE #TableName sys.sysname = N'rights'
DECLARE #OldTableName sys.sysname = N'rigths'
DECLARE #OldTableWithSchema NVARCHAR(256) = QUOTENAME(#TableSchema) + '.' + QUOTENAME(#OldTableName)
DECLARE #TableWithSchema NVARCHAR(256) = QUOTENAME(#TableSchema) + '.' + QUOTENAME(#TableName)
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = #TableSchema
AND TABLE_NAME = #TableName))
BEGIN
EXEC sp_rename #TableWithSchema, #OldTableName
END
DECLARE #Table TABLE ([LogicalName] varchar(128),[PhysicalName] varchar(128), [Type] varchar, [FileGroupName] varchar(128), [Size] varchar(128),
[MaxSize] varchar(128), [FileId]varchar(128), [CreateLSN]varchar(128), [DropLSN]varchar(128), [UniqueId]varchar(128), [ReadOnlyLSN]varchar(128), [ReadWriteLSN]varchar(128),
[BackupSizeInBytes]varchar(128), [SourceBlockSize]varchar(128), [FileGroupId]varchar(128), [LogGroupGUID]varchar(128), [DifferentialBaseLSN]varchar(128), [DifferentialBaseGUID]varchar(128),
[IsReadOnly]varchar(128), [IsPresent]varchar(128), [TDEThumbprint]varchar(128), [SnapshotUrl]varchar(128)
)
DECLARE #Path varchar(1000)='C:\Program Files\Microsoft SQL Server\MSSQL13.SQLEXPRESS\MSSQL\Backup\SQL2008backup.bak'
DECLARE #LogicalNameData varchar(128),#LogicalNameLog varchar(128)
INSERT INTO #table
EXEC('
RESTORE FILELISTONLY
FROM DISK=''' +#Path+ '''
')
SET #LogicalNameData=(SELECT LogicalName FROM #Table WHERE Type='D')
SET #LogicalNameLog=(SELECT LogicalName FROM #Table WHERE Type='L')
SELECT #LogicalNameData, #LogicalNameLog
use master;
declare #MasterData nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer\Parameters', N'SqlArg0', #MasterData output
select #MasterData=substring(#MasterData, 3, 255)
select #MasterData=substring(#MasterData, 1, len(#MasterData) - charindex('\', reverse(#MasterData)))
print #MasterData
declare #MasterLog nvarchar(512)
exec master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer\Parameters', N'SqlArg2', #MasterLog output
select #MasterLog=substring(#MasterLog, 3, 255)
select #MasterLog=substring(#MasterLog, 1, len(#MasterLog) - charindex('\', reverse(#MasterLog)))
print #MasterLog
declare #NewDefaultData nvarchar(512)
select isnull(#NewDefaultData, CONVERT(nvarchar(512), #MasterData))
declare #NewDefaultLog nvarchar(512)
select isnull(#NewDefaultLog, CONVERT(nvarchar(512), #MasterLog))
SET DEADLOCK_PRIORITY 10
ALTER DATABASE school
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE school FROM DISK=#Path
WITH
MOVE #LogicalNameData TO #NewDefaultData,
MOVE #LogicalNameLog TO #NewDefaultLog,
REPLACE
IF (EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = #TableSchema
AND TABLE_NAME = #OldTableName))
BEGIN
EXEC sp_rename #OldTableWithSchema, #TableName
END
Updated with new code but new error
The Master database is usually used for system tables and I have never seen it used for application tables. If by accident it was used you should restore the database under a different name and copy out the tables (and other user objects) to a user database. If you insist on using master (and as we say in Brooklyn only bad things can come from this) you need to do the following:
Put the database in single user mode (by using the -m parameter in the startup file)
From sqlcmd run this command (with the actual location of the backup file):
RESTORE DATABASE master
FROM DISK = 'c:\backups\master.bak'
WITH REPLACE;
You need to overwrite your current database with the backed up database. You can do this with the REPLACE option
The basic syntax is...
SET DEADLOCK_PRIORITY 10
ALTER DATABASE master
SET SINGLE_USER
WITH ROLLBACK IMMEDIATE;
restore database master from disk = 'c:\somefile.bak'
with replace

Is there a way to avoid MOVE errors on script restore?

I've searched for a while this problem and can't figure out a solution if there's none.
Every week we get new databases from clients. I developed a tool to restore our own databases in order to keep all databases to keep with the client ones.
The tool works for some databases but on others I get some errors because of the log files.
My script for restoring the database is the following
USE [master]
ALTER DATABASE[MyDataBase] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
RESTORE DATABASE[MyDataBase]
FROM DISK = N'MyDataBase.bak'
WITH NOUNLOAD,
REPLACE, STATS = 5
ALTER DATABASE[MyDataBase] SET MULTI_USER
I know if I use the MOVE command I can get over my problem, the thing is I have no way to know the files beforehand, meaning I can't really write any custom code to restore the databases.
Digging a bit deeper I found that I could print all my log files from the database with the following command
SELECT
DB_NAME([database_id]) [database_name]
, [file_id]
, [type_desc] [file_type]
, [name] [logical_name]
, [physical_name]
FROM sys.[master_files]
WHERE [database_id] IN (DB_ID('MyDataBase'))
ORDER BY [type], DB_NAME([database_id]);
but the files presented there have completly different names from the ones I get the error on.
Another important thing to note is that if I restore the database and then try to restore through tsql I can do the restore but I have a Server Agent Job renaming the files in order to keep things clean and after running that I'm unable to restore the database again giving the same errors that I was getting before restoring manually.
I have no clue if what I'm trying to achieve is achievable and if so how to achieve it. If anyone could give me some lights it would be amazing
RESTORE FILELISTONLY will tell you the files, and you can build up the RESTORE ... WITH MOVE from that:
EG
--backup database a to disk='c:\temp\a.bak'
declare #fn nvarchar(255) = 'c:\temp\a.bak';
declare #sql nvarchar(max) = concat('restore filelistonly from disk=''',#fn,'''');
declare #targetFolder nvarchar(max) = 'c:\temp\customer_123';
declare #dbname sysname = 'a_123';
declare #t table
(
LogicalName nvarchar(128),--, --Logical name of the file.
PhysicalName nvarchar(260),-- Physical or operating-system name of the file.
Type char(1),-- The type of file, one of:
FileGroupName nvarchar(128) NULL, -- Name of the filegroup that contains the file.
Size numeric(20,0),-- Current size in bytes.
MaxSize numeric(20,0),-- Maximum allowed size in bytes.
FileID bigint,-- File identifier, unique within the database.
CreateLSN numeric(25,0),-- Log sequence number at which the file was created.
DropLSN numeric(25,0) NULL, -- The log sequence number at which the file was dropped. If the file has not been dropped, this value is NULL.
UniqueID uniqueidentifier,-- Globally unique identifier of the file.
ReadOnlyLSN numeric(25,0) NULL, -- Log sequence number at which the filegroup containing the file changed from read-write to read-only (the most recent change),--.
ReadWriteLSN numeric(25,0) NULL, -- Log sequence number at which the filegroup containing the file changed from read-only to read-write (the most recent change),--.
BackupSizeInBytes bigint, -- Size of the backup for this file in bytes.
SourceBlockSize int, -- Block size of the physical device containing the file in bytes (not the backup device),--.
FileGroupID int,-- ID of the filegroup.
LogGroupGUID uniqueidentifier NULL, -- NULL.
DifferentialBaseLSN numeric(25,0) NULL, -- For differential backups, changes with log sequence numbers greater than or equal to DifferentialBaseLSN are included in the differential
DifferentialBaseGUID uniqueidentifier NULL, -- For differential backups, the unique identifier of the differential base.
IsReadOnly bit,-- 1 = The file is read-only.
IsPresent bit,-- 1 = The file is present in the backup.
TDEThumbprint varbinary(32) NULL, -- Shows the thumbprint of the Database Encryption Key. The encryptor thumbprint is a SHA-1 hash of the certificate with which the key is encrypted. For information about database encryption, see Transparent Data Encryption (TDE),--.
SnapshotURL nvarchar(360)-- NULL The URL for the Azure snapshot of the database file contained in the FILE_SNAPSHOT backup. Returns NULL if no FILE_SNAPSHOT backup.
);
insert into #t
exec (#sql);
with q as
(
select concat('restore database ',#dbname,' from disk=''',#fn,''' with ') l
union all
select concat('
move ''',LogicalName,''' to ''', #targetFolder, '\', LogicalName, case [type] when 'D' then '.mdf' when 'L' then '.ldf' else null end, ''' , ')
from #t
union all
select 'RECOVERY, STATS = 10'
)
select #sql = STRING_AGG(l,'
')
from q;
print (#sql);
exec (#sql );

Table already exists in a new SQL Server database

I'm writing a script to create a bunch of tables in SQL Server. As I write the script, I want to create and delete the database. The problem is that the I get an error saying that the object already exists.
Here is my example script
DECLARE #db_name varchar(20);
DECLARE #command varchar(100);
SET #db_name='testdb';
SET #command='DROP DATABASE ' + #db_name
IF EXISTS(SELECT * FROM sys.databases WHERE name=#db_name)
exec(#command)
SET #command='CREATE DATABASE ' + #db_name
EXEC(#command)
--listing databaes
SELECT name from master.dbo.sysdatabases
-- using our database
SET #command='USE ' + #db_name
EXEC(#command)
PRINT 'listing tables'
SET #command = 'SELECT table_name FROM ' + #db_name + '.INFORMATION_SCHEMA.TABLES WHERE table_type = "base TABLE"'
EXEC(#command)
CREATE TABLE stuff(
name VARCHAR(30) PRIMARY KEY NOT NULL,
weight INT,
quantity INT)
and the output I get is
name
------------
master
tempdb
model
msdb
testdb
SW
(6 rows affected)
listing tables
table_name
Error:
Msg 2714, Level 16, State 6, Server Orange, Line 22
There is already an object named 'stuff' in the database.
I run this on a Linux mint machine, a freshly installed SQL Server, and I use sqlcmd. I guess I can put a drop/delete command before the creating the table, but this shouldn't happen to begin with. What is going on here?
When you execute a USE statement from dynamic SQL, the database context reverts back to the original database context (master?) when the executed batch completes. You'll need to add a USE to the CREATE TABLE script and execute it using dynamic SQL too:
SET #command = N'USE' + QUOTENAME(#db_name) + N';
CREATE TABLE stuff(
name VARCHAR(30) PRIMARY KEY NOT NULL,
weight INT,
quantity INT);
';
bind the create table statement inside a object existence check. like this
IF OBJECT_ID('stuff') IS NULL
BEGIN
CREATE TABLE stuff(
name VARCHAR(30) PRIMARY KEY--NOT NULL is not needed as the primary key does not allow NULL,
weight INT,
quantity INT)
END

SQL Server 2012 -- xp_fileexist returns 0 when checking for file on local machine

The SQL server exists on the same machine I am physically logged into, and xp_fileexist is failing to recognize any files on the D drive, which is not a network drive. I already configured xp_cmdshell and restarted the SQL server instance. Any other ideas?
Yup, we had the same problem. On SQL Server 2008, our legacy xp_fileexist code worked fine, but on SQL Server 2012... nope.
It would work if we ran the xp_fileexist command as ourselves (with Admin rights) but not when we ran it as a SQL Server user, who didn't exist as an Active Directory user. Even if we changed the security on that folder to give Everyone full permissions, the xp_fileexist would fail, always returning a 0, as if a file within that folder didn't exist.
However, what did work was to use dir from within a Stored Procedure, and test if the file existed that way. (Yeah, I know... I'm rolling my eyes myself... this is dodgy..)
Here's the Stored Procedure I wrote, based on suggestions on this site :
CREATE PROCEDURE [dbo].[DoesFileExist]
(
#directoryName NVARCHAR(500),
#filename NVARCHAR(500)
)
AS
BEGIN
-- Does a file exist in a particular folder ?
--
-- EXEC [dbo].[DoesFileExist] 'D:\MyFiles', 'SomeExcelFile.xls'
--
DECLARE #bFileExists INT
DECLARE #cmd nvarchar(300);
SELECT #cmd = 'dir ' + #directoryName + '\' + #filename;
DECLARE #dir TABLE ([output] varchar( 2000 ))
INSERT INTO #dir
EXEC master.dbo.xp_cmdshell #cmd;
-- Uncomment the following line, if you want to see what
-- a "dir" looks like from SQL Server !!
-- SELECT * FROM #dir
if EXISTS(SELECT * FROM #dir WHERE [output] LIKE '%' + #filename + '%' )
BEGIN
-- File *was* found in this folder
SET #bFileExists = 1
END
ELSE
BEGIN
-- File was NOT found in this folder
SET #bFileExists = 0
END
SELECT #bFileExists
END
You can call this SP simply by passing it a folder name and a filename:
EXEC [dbo].[DoesFileExist] 'D:\MyFiles', 'SomeExcelFile.xls'
And yes, strangely, it does seem to work, for the SQL Server users who can't use xp_fileexist.
Remember that, to use this code, your SQL Server user must have permissions to use xp_cmdshell :
GRANT EXECUTE ON xp_cmdshell TO YourSQLServerUser

MS SQL Database Table Prefix from Previous Owner

I have an MS SQL 2000 database that was backed up from a public server and restored at a test location for an upgrade test. The problem is that the user that had access permission on the public server does not exist on the testing server, and now all tables are prefixed with that username (which requires ALL queries against those tables to be changed!)
Is there any quick way to fix this? I have changed the database owner but this did not help.
Create the login and users, but find out the SID from sysusers
EXEC sp_addlogin 'TheLogin', 'ThePassword', #sid = ???
EXEC sp_adduser 'TheLogin','TheUser'
Note: SQL Server 2000 so can't use CREATE LOGIN or CREATE USER
Ok, found the answer - the OBJECT owner must be changed to DBO, negating the need to prefix references to your object in your SQL scripts/queries - the object in this case being the database table(s)
Here is a script that will change the owner for objects within a database (not my own code)
DECLARE #currentObject nvarchar(517)
DECLARE #qualifiedObject nvarchar(517)
DECLARE #currentOwner varchar(50)
DECLARE #newOwner varchar(50)
SET #currentOwner = 'old_owner'
SET #newOwner = 'dbo'
DECLARE alterOwnerCursor CURSOR FOR
SELECT [name] FROM dbo.sysobjects
WHERE xtype = 'U' or xtype = 'P'
AND LEFT([name], 2) <> 'dt'
OPEN alterOwnerCursor
FETCH NEXT FROM alterOwnerCursor INTO #currentObject
WHILE ##FETCH_STATUS = 0
BEGIN
SET #qualifiedObject = CAST(#currentOwner as varchar) + '.' + CAST(#currentObject as varchar)
EXEC sp_changeobjectowner #qualifiedObject, #newOwner
FETCH NEXT FROM alterOwnerCursor INTO #currentObject
END
CLOSE alterOwnerCursor
DEALLOCATE alterOwnerCursor

Resources