Creating Stream DATABASE in a remote server - sql-server

Whith the assistance of a very good fellow from this forum (Mr. DJHnz) i solve my first issue regarding the creation of a stream database
Now i'm facing another issue
I'm giving you the code:
USE [master]
GO
/****** Object: StoredProcedure [dbo].[sp_AddStreamDB] Script Date: 12/21/2009 09:55:47 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_AddStreamDB](
-- Add the parameters for the stored procedure here
#DPath varchar(MAX),
#DBName varchar(50),
#Qchar varchar(1) = "'"
) AS
BEGIN_TRY:
SET QUOTED_IDENTIFIER ON;
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE
#ErrMsg nvarchar(4000),
#DBName1 varchar(50),
#DBName2 varchar(50),
#DBNamefs varchar(50),
#DBNamelog varchar(50),
#FileGroupN varchar(100),
#DATName varchar(MAX),
#LOGName varchar(MAX),
#FSName varchar(MAX),
#CreateSdb nvarchar(MAX),
#Statement nvarchar(MAX)
SET #DBName1 = (#DBName + '1')
SET #DBName2 = (#DBName + '2')
SET #DBNamefs = (#DBName + 'fs')
SET #DBNamelog = (#DBName + 'log')
SET #FileGroupN = (#DBname + 'StreamGroup')
SET #DATName = (#Qchar + #DPath + #DBName +'_dat.mdf' + #Qchar)
SET #LOGName = (#Qchar + #DPath + #DBName +'_log.ldf' + #Qchar)
SET #FSName = (#Qchar + #DPath + #DBName + '_fs' + #Qchar)
SET #CreateSdb =('CREATE DATABASE ' + #DBName + ' ON PRIMARY (NAME = ' + #DBName1 + ', FILENAME = ' + #DATName + '), FILEGROUP ' + #FileGroupN + ' CONTAINS FILESTREAM (NAME = ' + #DBNamefs + ', FILENAME = ' + #FSName + ') LOG ON (NAME = ' + #DBNamelog + ', FILENAME = ' + #LOGName + ')')
SET #Statement = ' '
BEGIN_CATCH:
SELECT ERROR_MESSAGE() as ErrorMessage;
SELECT #ErrMsg = ERROR_MESSAGE()
EXEC master.sys.sp_executesql #CreateSdb, #Statement
RAISERROR (#ErrMsg,1,1)
RETURN 0
END_CATCH:
END_TRY:
So far to point everything works fine until the remote server tries to create the neccessary files for the stream DB
then he gives the following error:
Unable to open the physical file "C:\sqlDATA\RemoteDB_fs". Operating system error -2147024891: "0x80070005(Access is denied.)".
The name of the drive C:\ lies on the remote machine (a machine near to me in the same network with Windows server 2003; later i will run the program for my ISP machine)
the subfolder sqlDATA\ is already there i have created manually as it should be.
In my local machine the all package works fine and the DATA BASE created fine but the issue starts when i use remote server.
NOW I NEED THE HELP:
Why i receive this ERROR?

The SQL Server service account does not have rights on C:\SQLData

As #gbn explained and also:
C:\sqlDATA directory must exist.
The \RemoteDB_fs sub-directory for file-stream must not exist.

Related

Alter Schema Transfer fails even when I'm a db-owner

I asked this on GitHub here, but I think we can turn into a more generic question to get some helpful ideas faster.
First, I ran the script here, which shows that I am a member of the db-owner group.
This is on the install script for an older tool called AutoEdit. Despite the issue below, I'm able to turn on AutoAudit for specific tables and it's working okay.
The supplied script stores a few stored proc under a schema with my username, then tries to transfer them to the "audit" schema later. The AutoEdit concepts and stored procs are all actually working, but now I need to clean it up and put in another environment.
Error is:
Cannot find the object 'pAutoAudit', because it does not exist or you do not have permission.
It created the stored proc as
"Corp\myuserid.pAutoAudit"
I added two print statements to help debug:
-- This is the line of code (the EXEC below) that is causing the issue:
print Concat('#AuditSchema=', #AuditSchema)
SET #Sql = 'ALTER SCHEMA ' + quotename(#AuditSchema) + ' TRANSFER dbo.pAutoAudit'
print Concat('#Sql=', #Sql)
EXEC (#Sql)
Above shows:
#AuditSchema=Audit
#Sql=ALTER SCHEMA [Audit] TRANSFER dbo.pAutoAudit
The schema Audit exists, and it has one stored proc in it: pAutoAuditArchive.
I have added a related question here: SQL Server setting that changes schema from dbo
To fix this specific problem, I saw the correct syntax from the Lauren answer here, like this:
ALTER SCHEMA NewSchema TRANSFER [OldSchema].[TableName]
The following script temporarily fixes the issue. I have to study more how to fix the original script if indeed it has an error:
use myDbname
Declare #AuditSchema varchar(32)
Declare #OldSchema varchar(32)
Declare #SQL varchar(max)
Set #AuditSchema = 'Audit'
Set #OldSchema = 'Corp\myuser'
-- ALTER SCHEMA NewSchema TRANSFER [OldSchema].[TableName]
SET #SQL = 'ALTER SCHEMA ' + quotename(#AuditSchema) + ' TRANSFER ' + quotename(#OldSchema) + '.pAutoAudit'
print Concat('#SQL=', #SQL)
EXEC (#SQL)
SET #SQL = 'ALTER SCHEMA ' + quotename(#AuditSchema) + ' TRANSFER ' + quotename(#OldSchema) + '.pAutoAuditAll'
EXEC (#SQL)
SET #SQL = 'ALTER SCHEMA ' + quotename(#AuditSchema) + ' TRANSFER ' + quotename(#OldSchema) + '.pAutoAuditDrop'
EXEC (#SQL)
SET #SQL = 'ALTER SCHEMA ' + quotename(#AuditSchema) + ' TRANSFER ' + quotename(#OldSchema) + '.pAutoAuditDropAll'
EXEC (#SQL)
SET #SQL = 'ALTER SCHEMA ' + quotename(#AuditSchema) + ' TRANSFER ' + quotename(#OldSchema) + '.pAutoAuditRebuild'
EXEC (#SQL)
SET #SQL = 'ALTER SCHEMA ' + quotename(#AuditSchema) + ' TRANSFER ' + quotename(#OldSchema) + '.pAutoAuditRebuildAll'
EXEC (#SQL)
SET #SQL = 'ALTER SCHEMA ' + quotename(#AuditSchema) + ' TRANSFER ' + quotename(#OldSchema) + '.pAutoAuditSetTriggerState'
EXEC (#SQL)
SET #SQL = 'ALTER SCHEMA ' + quotename(#AuditSchema) + ' TRANSFER ' + quotename(#OldSchema) + '.pAutoAuditSetTriggerStateAll'
EXEC (#SQL)
However, to fix the "AutoEdit" script referenced in the question, the problem can be corected by adding this code to AutoEdit or running it before AutoEdit. Apparently, it assumes you are in the "dbo" default_schema. You might have to set the value back to the original value if needed after the script.
DECLARE #SQL2 VARCHAR(max)
SET #SQL2 = 'ALTER USER ' + quotename(current_user) + ' WITH DEFAULT_SCHEMA = dbo'
print Concat('#SQL2=', #SQL2)
exec (#SQL2)
The better fix for when I moved it to another environment, was to change all the "Create Proc xxxx" to "Create Proc dbo.xxxx".

Is there a function to compress 'bak' file in sql script?

In SQL Server, I want to clear personal info and backup it
Backup original DB
Restore as another DB name
Clear personal info in another DB
Backup another DB
Delete rest files
Zip Backup DB
I finished 1~5. but couldn't find a way to do 6.
I Want to compress bak file to zip here.
For instance, below code can be used in Powershell script. Is there a way to use this .Net function in SQL script?
[System.IO.Compression.ZipFile]::CreateFromDirectory($CurrentPath, $DeployHistoryFilePath)
Below is my full script.
DECLARE #DBName NVARCHAR(MAX) = N'TestDB'
DECLARE #BackupPath NVARCHAR(MAX) = N'D:\Database\Backup'
EXEC ('master.dbo.xp_create_subdir N'''+ #BackupPath +'''')
DECLARE #BackupName NVARCHAR(MAX) = N'OnCube_' + REPLACE(REPLACE(REPLACE(CONVERT(NVARCHAR(MAX), GETDATE(), 120), N'-', N''), N':', N''), N' ', N'_')
DECLARE #DiskFile NVARCHAR(MAX) = #BackupPath + N'\' + #BackupName + N'.bak'
BACKUP DATABASE #DBName TO DISK = #DiskFile
DECLARE #SQL NVARCHAR(MAX) = 'SELECT TOP (1) #OriginalMdf = name FROM ' + #DBName + '.sys.database_files WHERE file_id = 1'
DECLARE #OriginalMdf NVARCHAR(MAX)
EXEC sp_executesql #SQL, N'#OriginalMdf NVARCHAR(MAX) OUT', #OriginalMdf out
SET #SQL = 'SELECT TOP (1) #OriginalLdf = name FROM ' + #DBName + '.sys.database_files WHERE file_id = 2'
DECLARE #OriginalLdf NVARCHAR(MAX)
EXEC sp_executesql #SQL, N'#OriginalLdf NVARCHAR(MAX) OUT', #OriginalLdf out
DECLARE #PartialMdf NVARCHAR(MAX) = #BackupPath + N'\' + #BackupName + N'.mdf'
DECLARE #PartialLdf NVARCHAR(MAX) = #BackupPath + N'\' + #BackupName + N'_0.ldf'
RESTORE FILELISTONLY FROM DISK = #DiskFile
RESTORE DATABASE #BackupName
FROM DISK = #DiskFile
WITH MOVE #OriginalMdf TO #PartialMdf,
MOVE #OriginalLdf TO #PartialLdf
EXEC (N'
USE [' + #BackupName + ']
UPDATE Person
SET
PatientNo = NULL
, PatientName = N''Cleared'' + CONVERT(NVARCHAR(MAX), RawID)
, RoomNo = NULL
, BedNo = NULL
, Birthday = NULL
, Sex = NULL
, Address = NULL
, AdmitDate = NULL
, AdmitNo = NULL
, Description = NULL
, DischargedDate = NULL
')
DECLARE #ClearedDiskFile NVARCHAR(MAX) = #BackupPath + N'\' + #BackupName + N'_PatientInfoCleared.bak'
BACKUP DATABASE #BackupName TO DISK = #ClearedDiskFile
EXEC('DROP DATABASE [' + #BackupName + ']')
EXEC ('xp_cmdshell ''del "' + #DiskFile + '"''')
-- I Want to compress bak file to zip here
-- For instance, below code can be used in Powershell script. Is there a way to use this .Net function in SQL script?
-- [System.IO.Compression.ZipFile]::CreateFromDirectory($CurrentPath, $DeployHistoryFilePath)
PRINT N'Success to make ' + #ClearedDiskFile + '. Patient informations are all cleared'
Is there a way to use this .Net function in SQL script?
Yes, you can use SQL CLR with C#
see samples Using 7-zip and SharpZipLib here:
also , you can create zip file from SQL without Powershell script:
Create zip file from SQL Server

How to create a table inside of recently created database with dynamic sql?

I want to populate a set of tables and procedures into new databases programmatically.
Then I prepared a Initialize Script and I will use it inside a procedure who must created new databases.
I tried with a simple example and didn't work:
CREATE PROCEDURE PROCEDURETOREPLICATECOMMONSCHEMA
#databaseName NVARCHAR(40)
AS
BEGIN
DECLARE #sqlCreation NVARCHAR(MAX);
SET #sqlCreation = '
USE MASTER;
EXEC(''CREATE DATABASE ' + #databaseName + ''');
EXEC(''USE ' + #databaseName + ''');
CREATE TABLE Testing
(
TestPk int,
TestDescription nvarchar(80)
);
';
PRINT #sqlCreation;
EXEC sp_executesql #sqlCreation;
END
GO
When I execute this procedure, it creates the table Testing inside master database instead of TestDatabase1.
EXEC PROCEDURETOREPLICATECOMMONSCHEMA 'TestDatabase1'
GO
First create the database, then create the table (two separate statements):
CREATE PROCEDURE PROCEDURETOREPLICATECOMMONSCHEMA
#databaseName NVARCHAR(40)
AS
BEGIN
DECLARE #sqlCreation NVARCHAR(MAX);
SET #sqlCreation = 'USE MASTER;
EXEC(''CREATE DATABASE ' + #databaseName + ''');';
EXEC sp_executesql #sqlCreation;
SET #sqlCreation = 'EXEC(''USE ' + #databaseName + ''');
CREATE TABLE ' + #databaseName + '.dbo.Testing
(
TestPk int,
TestDescription nvarchar(80)
);';
EXEC sp_executesql #sqlCreation;
END
GO
Please make use of the below code. Its working fine with SQL Server 2012.
CREATE PROCEDURE PROCEDURETOREPLICATECOMMONSCHEMA
#databaseName NVARCHAR(40)
AS
BEGIN
BEGIN
EXEC('USE MASTER;CREATE DATABASE ' + #databaseName + ';')
EXEC('CREATE TABLE ' + #databaseName + '.dbo.Testing(TestPk int,TestDescription nvarchar(80));')
END
END
GO

SQL Server multiple shrink operations

I'm trying to shrink all databases (files and logs) in SQL Server 2008 R2.
I have finished the script, but the problem is that when I loop over all databases and execute the query to do shrink file the first 3 or 4 shrinks work but them I have this error :
Msg 0, Level 11, State 0, Line 0
A severe error occurred on the current command. The results, if any,
should be discarded.
The script :
declare #db_name as varchar(30)
declare #db_recorvery_model as varchar(30)
declare #db_files_name as varchar(250)
declare #db_files_physical_name as varchar(250)
declare get_files cursor for
select b.name, a.name
from sys.master_files as a,
sys.databases as b
where a.database_id = b.database_id
order by b.name
open get_files
fetch next from get_files into #db_files_name, #db_files_physical_name
set #db_files_name = (select #db_files_name)
set #db_files_physical_name = (select #db_files_physical_name)
DECLARE #Command as nvarchar(max)
set #Command=''
while(##FETCH_STATUS=0)
BEGIN
if (#db_files_name='master' or #db_files_name='msdb' or #db_files_name='tempdb' or #db_files_name='model')
BEGIN
print 'Bases de dados do sql server: '+#db_files_name
END
ELSE
BEGIN
set #Command = 'USE ' + '[' + #db_files_name + '] DBCC SHRINKFILE ("'+#db_files_physical_name+'", 1 )'
EXEC sp_executesql #Command
print #Command
END
fetch next from get_files into #db_files_name, #db_files_physical_name
set #db_files_name = (select #db_files_name)
set #db_files_physical_name = (select #db_files_physical_name)
END
close get_files
deallocate get_files
Does anyone have any ideas ?
PS: I know that I shouldn't shrink but is a very special environment and not productive.
Can you determine which database flags the error? Can you try running your script on the single database that has the problem and see if it is consistently the same database that triggers the error? Perhaps it's a special database that you've missed that cannot be shrunk that way.
I have a similar environment containing temp databases that are not for long term storage, and I use the following script which has worked perfectly for hundreds of databases:
CREATE procedure [dbo].[ShrinkLog]
#DB varchar(200)
as
declare #LogFile varchar(200)
declare #Sql varchar(500)
SELECT #LogFile = name
FROM sys.master_files
where type_desc = 'LOG'
and db_name(database_id) = #DB
set #Sql = '
Use [' + #DB + ']
DBCC SHRINKFILE([' + #LogFile + '], 1)
'
print(#sql)
exec(#sql)
Keep in mind also that you don't want to run this command unless your server has plenty of hard drive/memory space as well.
Best regards,
If you want to do a log shrink, this will be the best code. I am using it for a while and it never crash to me.
declare #SQL nvarchar(max)
select #SQL = coalesce(#SQL + char(13) + char(10),'') + N'
Use ' + QUOTENAME(d.[name]) + ';' + CHAR(13) + '
ALTER DATABASE ' + QUOTENAME(d.[name]) + ' SET RECOVERY SIMPLE;
DBCC SHRINKFILE (' + quotename(mf.[name],'''') + ', 1);
ALTER DATABASE ' + QUOTENAME(d.[name]) + ' SET RECOVERY FULL;'
FROM sys.databases d
INNER JOIN sys.master_files mf ON [d].[database_id] = [mf].[database_id]
WHERE
d.[database_id] > 4 --no sys dbs
AND d.recovery_model = 1
AND d.is_read_only = 0
AND mf.[type] = 1 --log files
ORDER BY d.name
--print #SQL
execute (#SQL)

What is the best way to copy a database?

When I want to make a copy of a database, I always create a new empty database, and then restore a backup of the existing database into it. However, I'm wondering if this is really the least error-prone, least complicated, and most efficient way to do this?
It is possible to skip the step of creating the empty database. You can create the new database as part of the restore process.
This is actually the easiest and best way I know of to clone a database. You can eliminate errors by scripting the backup and restore process rather than running it through the SQL Server Management Studio
There are two other options you could explore:
Detach the database, copy the .mdf file and re-attach.
Use SQL Server Integration Services (SSIS) to copy all the objects over
I suggest sticking with backup and restore and automating if necessary.
Here's a dynamic sql script I've used in the past. It can be further modified but it will give you the basics. I prefer scripting it to avoid the mistakes you can make using the Management Studio:
Declare #OldDB varchar(100)
Declare #NewDB varchar(100)
Declare #vchBackupPath varchar(255)
Declare #query varchar(8000)
/*Test code to implement
Select #OldDB = 'Pubs'
Select #NewDB = 'Pubs2'
Select #vchBackupPath = '\\dbserver\C$\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Backup\pubs.bak'
*/
SET NOCOUNT ON;
Select #query = 'Create Database ' + #NewDB
exec(#query)
Select #query = '
Declare #vBAKPath varchar(256)
declare #oldMDFName varchar(100)
declare #oldLDFName varchar(100)
declare #newMDFPath varchar(100)
declare #newLDFPath varchar(100)
declare #restQuery varchar(800)
select #vBAKPath = ''' + #vchBackupPath + '''
select #oldLDFName = name from ' + #OldDB +'.dbo.sysfiles where filename like ''%.ldf%''
select #oldMDFName = name from ' + #OldDB +'.dbo.sysfiles where filename like ''%.mdf%''
select #newMDFPath = physical_name from ' + #NewDB +'.sys.database_files where type_desc = ''ROWS''
select #newLDFPath = physical_name from ' + #NewDB +'.sys.database_files where type_desc = ''LOG''
select #restQuery = ''RESTORE DATABASE ' + #NewDB +
' FROM DISK = N'' + '''''''' + #vBAKpath + '''''''' +
'' WITH MOVE N'' + '''''''' + #oldMDFName + '''''''' +
'' TO N'' + '''''''' + #newMDFPath + '''''''' +
'', MOVE N'' + '''''''' + #oldLDFName + '''''''' +
'' TO N'' + '''''''' + #newLDFPath + '''''''' +
'', NOUNLOAD, REPLACE, STATS = 10''
exec(#restQuery)
--print #restQuery'
exec(#query)
Backup and Restore is the most straight-forward way I know. You have to be careful between servers as security credentials don't come with the restored database.
The Publish to Provider functionality has worked great for me. See Scott Gu's Blog Entry.
If you need something really robust look at redgate software's tools here...if you are doing much SQL at all, these are worth the $$.
::================ BackUpAllMyDatabases.cmd ============= START
::BackUpAllMyDatabases.cmd
:: COMMAND LINE BATCH SCRIPT FOR TAKING BACKUP OF ALL DATABASES
::RUN THE SQL SCRIPT VIA THE COMMAND LINE WITH LOGGING
sqlcmd -S localhost -e -i "BackUpAllMyDatabases.sql" -o Result_Of_BackUpAllMyDatabases.log
::VIEW THE RESULTS
Result_Of_BackUpAllMyDatabases.log
::pause
::================ BackUpAllMyDatabases.cmd ============= END
--=================================================BackUpAllMyDatabases.sql start
DECLARE #DBName varchar(255)
DECLARE #DATABASES_Fetch int
DECLARE DATABASES_CURSOR CURSOR FOR
select
DATABASE_NAME = db_name(s_mf.database_id)
from
sys.master_files s_mf
where
-- ONLINE
s_mf.state = 0
-- Only look at databases to which we have access
and has_dbaccess(db_name(s_mf.database_id)) = 1
-- Not master, tempdb or model
--and db_name(s_mf.database_id) not in ('Master','tempdb','model')
group by s_mf.database_id
order by 1
OPEN DATABASES_CURSOR
FETCH NEXT FROM DATABASES_CURSOR INTO #DBName
WHILE ##FETCH_STATUS = 0
BEGIN
declare #DBFileName varchar(256)
set #DBFileName = #DbName + '_' + replace(convert(varchar, getdate(), 112), '-', '.') + '.bak'
--REMEMBER TO PUT HERE THE TRAILING \ FOR THE DIRECTORY !!!
exec ('BACKUP DATABASE [' + #DBName + '] TO DISK = N''D:\DATA\BACKUPS\' +
#DBFileName + ''' WITH NOFORMAT, INIT, NAME = N''' +
#DBName + '-Full Database Backup'', SKIP, NOREWIND, NOUNLOAD, STATS = 100')
FETCH NEXT FROM DATABASES_CURSOR INTO #DBName
END
CLOSE DATABASES_CURSOR
DEALLOCATE DATABASES_CURSOR
--BackUpAllMyDatabases==========================end
--======================RestoreDbFromFile.sql start
-- Restore database from file
-----------------------------------------------------------------
use master
go
declare #backupFileName varchar(100), #restoreDirectory varchar(100),
#databaseDataFilename varchar(100), #databaseLogFilename varchar(100),
#databaseDataFile varchar(100), #databaseLogFile varchar(100),
#databaseName varchar(100), #execSql nvarchar(1000)
-- Set the name of the database to restore
set #databaseName = 'ReplaceDataBaseNameHere'
-- Set the path to the directory containing the database backup
set #restoreDirectory = 'ReplaceRestoreDirectoryHere' -- such as 'c:\temp\'
-- Create the backup file name based on the restore directory, the database name and today's date
#backupFileName = #restoreDirectory + #databaseName + '-' + replace(convert(varchar, getdate(), 110), '-', '.') + '.bak'
-- set #backupFileName = 'D:\DATA\BACKUPS\server.poc_test_fbu_20081016.bak'
-- Get the data file and its path
select #databaseDataFile = rtrim([Name]),
#databaseDataFilename = rtrim([Filename])
from master.dbo.sysaltfiles as files
inner join
master.dbo.sysfilegroups as groups
on
files.groupID = groups.groupID
where DBID = (
select dbid
from master.dbo.sysdatabases
where [Name] = #databaseName
)
-- Get the log file and its path
select #databaseLogFile = rtrim([Name]),
#databaseLogFilename = rtrim([Filename])
from master.dbo.sysaltfiles as files
where DBID = (
select dbid
from master.dbo.sysdatabases
where [Name] = #databaseName
)
and
groupID = 0
print 'Killing active connections to the "' + #databaseName + '" database'
-- Create the sql to kill the active database connections
set #execSql = ''
select #execSql = #execSql + 'kill ' + convert(char(10), spid) + ' '
from master.dbo.sysprocesses
where db_name(dbid) = #databaseName
and
DBID <> 0
and
spid <> ##spid
exec (#execSql)
print 'Restoring "' + #databaseName + '" database from "' + #backupFileName + '" with '
print ' data file "' + #databaseDataFile + '" located at "' + #databaseDataFilename + '"'
print ' log file "' + #databaseLogFile + '" located at "' + #databaseLogFilename + '"'
set #execSql = '
restore database [' + #databaseName + ']
from disk = ''' + #backupFileName + '''
with
file = 1,
move ''' + #databaseDataFile + ''' to ' + '''' + #databaseDataFilename + ''',
move ''' + #databaseLogFile + ''' to ' + '''' + #databaseLogFilename + ''',
norewind,
nounload,
replace'
exec sp_executesql #execSql
exec('use ' + #databaseName)
go
-- If needed, restore the database user associated with the database
/*
exec sp_revokedbaccess 'myDBUser'
go
exec sp_grantdbaccess 'myDBUser', 'myDBUser'
go
exec sp_addrolemember 'db_owner', 'myDBUser'
go
use master
go
*/
--======================RestoreDbFromFile.sql

Resources