SQL Server........ backup only a few databases - sql-server

I am using the stored procedure shown here for taking backups of databases from SQL Server.
It takes all backups for around 20 databases, now I want little change in the stored procedure.
It want below databases backups to pick through loop, how to modify existing stored procedure. Thanks
Emp_DB
Salary_DB
Company_DB
Attendance_DB
Code:
CREATE PROCEDURE Backupdbs
AS
BEGIN
DECLARE c1 CURSOR FOR
SELECT name FROM sys.databases WHERE database_id > 4
DECLARE #dbname varchar(100)
DECLARE #fname varchar(100)
OPEN C1
FETCH NEXT FROM c1 INTO #dbname
WHILE (##fetch_status = 0)
-- here, you're missing a
-- BEGIN
SET #fname = 'D:\Backup\'+#dbname+'.bak'
BACKUP DATABASE #dbname TO disk=#fname
FETCH NEXT FROM cl INTO #dbname
END
CLOSE c1
DEALLOCATE c1
END IF
Thanks
mg

A better scalable solution would be to have your own list of database names you want to back up, possibly with a groupId.
You can then pass a #groupId parameter and run a batch of database backups for the group or set of databases you choose - eg you can group large databases together, small together, frequently modified etc
So for example you could have the following table
create table BackupSets (
id int identity(1,1) primary key,
GroupId int,
[Name] sysname
)
and use it instead of sys.databases
select [Name] from BackupSets where groupId=#GroupId
You could also have a process as part of your backup to check for any names in sys.databases that don't exist in your list and insert them.

You could just add the databases in question to your where clause in your cursor query against sys.databases.
CREATE PROCEDURE Backupdbs
AS
BEGIN
DECLARE c1 CURSOR FOR
SELECT name FROM sys.databases WHERE database_id > 4
and name IN ('Emp_DB','Salary_DB','Company_DB','Attendance_DB')
DECLARE #dbname varchar(100)
DECLARE #fname varchar(100)
OPEN C1
FETCH NEXT FROM c1 INTO #dbname
WHILE (##fetch_status = 0)
-- here, you're missing a
-- BEGIN
SET #fname = 'D:\Backup\'+#dbname+'.bak'
BACKUP DATABASE #dbname TO disk=#fname
FETCH NEXT FROM cl INTO #dbname
END
CLOSE c1
DEALLOCATE c1
END IF

Related

How to declare a variable that lists all the existing databases on my server with the Microsoft SQL Server Management Studio

I need to create a variable that lists all the existing databases in my system, because I need it and I don't know how to do it. I have tried to create variables like this one:
DECLARE #nombreBD INT;
SET #nombreBD = (SELECT [database_id] FROM sys.databases Where name = 'model' )
SELECT #nombreBD AS Database_ID
PRINT #nombreBD
GO
This variable gets me only the name I put in the "WHERE" parameter but I need to get them all.
The table sys.databases shows you all the existing databases in the system and I need to get a boolean value from it, I thought to get it from the column "database_id" that's why I declared this variable.
This creates a table name #DBList with a column nombreBD
and inserts the database_id to the column,
then it shows all your sql-server database database_id
BEGIN
DECLARE #DBList TABLE (nombreBD INT)
INSERT INTO #DBList(nombreBD) SELECT database_id FROM sys.databases
SELECT * FROM #DBList
END
Is that what you need ?
To achieve what you want, you will need to use some dynamic SQL. Something like this ought to work for your case:
DECLARE #DBList TABLE (nombre varchar(50));
INSERT INTO #DBList(nombre) SELECT name FROM sys.databases
WHERE name NOT IN ('master','tempdb','msdb');
declare #name nvarchar(50);
declare #sql nvarchar(2000);
DECLARE db_Cursor CURSOR FOR
SELECT nombre FROM #DBList;
OPEN db_Cursor;
FETCH NEXT FROM db_Cursor INTO #name;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sql = N'USE ' + #name + N';'
exec sp_executesql #sql;
SET #sql = N'SELECT DB_NAME() AS DatabaseName, ''guest'' AS Database_User, [permission_name], [state_desc]
FROM sys.database_permissions WHERE [grantee_principal_id] = DATABASE_PRINCIPAL_ID(''guest'') AND [state_desc] LIKE ''GRANT%'' AND [permission_name] = ''CONNECT'';';
exec sp_executesql #sql;
FETCH NEXT FROM db_Cursor INTO #name;
END;
CLOSE db_Cursor;
DEALLOCATE db_Cursor;
Notice that I have changed the table variable to hold the database names, not their ids. This is because the USE statement takes the name not the id.
The cursor loops through the values, builds the various sql statements and executes them.

MS SQL loop through all DBs. Script works to alter table but not stored procedure

I use a piece of code to loop through all the databases on an MS SQL server. It works fine for altering a column on a table and also for updating the data. But I continue to get errors when trying to alter a stored procedure. Here is the code:
use master
declare #dbname varchar(100)
,#sql varchar(max)
declare db_cur cursor for
SELECT name
FROM sys.databases where ([name] like 'ce%')
and [state] = 0
open db_cur
fetch next from db_cur into #dbname
while ##FETCH_STATUS = 0
begin
set #sql=
'ALTER TABLE ['+#dbname+'].[dbo].MyStuff
ADD myNewColumn bit NULL DEFAULT(0)
'
exec(#sql)
fetch next from db_cur into #dbname
end
close db_cur
deallocate db_cur
So the code above works perfectly fine. But when I alter that code to instead do an alter stored procedure I receive the message below:
'CREATE/ALTER PROCEDURE' does not allow specifying the database name as a prefix to the object name.
I realized that the message stated I can't use the database name in the front of the procedure like I was doing here: ALTER procedure ['+#dbname+'].[dbo].[spSelectSomething]. But I haven't been able to figure out a way around the issue. Thanks for your help.
You need to nest dynamic SQL for this task because a proc CREATE or ALTER must be the first statement in the batch:
SET #sql= N'EXEC(N''USE ' + QUOTENAME(#dbname) + N';EXEC(N''''CREATE PROC...;'''')'')';

Restore by SQL-Script / wait for restore to finish

In my script for restoring databases, I came to another problem. After restoring a database I want to edit some tables of it. So after the common restore query:
RESTORE DATABASE #DBname
FROM DISK = #BackupFileLocation
GO
I want to edit the mentioned tables. The problem is that I need to use some variables for editing the tables after the restore, that I declare before it (I need them there to). And it seems that GO kind of resets all variables so I can't use them afterwards. But if I try it without GO, it jumps over the restore query and says that the databases I want to edit, don't exist.
My Question: Is there another way to wait for the restore to finish until it continues editing the tables?
Here’s one way: set up a temp table (#table, not #variable), populate it with your values, then set your variables to these values. For example:
-- This will drop the temp table if it already exists.
-- Essential for repetitive testing!
IF object_id('tempdb.dbo.#Foo') is not null
DROP TABLE #Foo
GO
CREATE TABLE #Foo
(
DBName varchar(100) not null
,BackupFileLocation varchar(1000) not null
)
INSERT #Foo values ('MyDatabase', 'C:\SQL_Backups\SampleDBs')
DECLARE
#DBname varchar(100)
,#BackupFileLocation varchar(1000)
SELECT
#DBname = DBName
,#BackupFileLocation = BackupFileLocation
from #Foo
PRINT '-- Before restore --------------------'
PRINT #DBname
PRINT #BackupFileLocation
-- Note: I did not test this statement
RESTORE DATABASE #DBname
FROM DISK = #BackupFileLocation
GO
DECLARE
#DBname varchar(100)
,#BackupFileLocation varchar(1000)
SELECT
#DBname = DBName
,#BackupFileLocation = BackupFileLocation
from #Foo
PRINT ''
PRINT '-- After restore --------------------'
PRINT #DBname
PRINT #BackupFileLocation
GO

How can I create an UPDATE statement from a large XML data type?

I am working with two databases that are not accessible at the same time. One of the standard methods of dealing with this I've seen on here is to create dynamic sql for loading one from the other.
I created a stored procedure that would drop update statements from an existing database. My issue is what happens when the XML is too large to be held in a VARCHAR(max).
Here is a relevant snippet from my attempt where field2 is actually of an XML data type:
DECLARE #field1Col VARCHAR(50)
DECLARE #field2Col VARCHAR(max)
DECLARE #vsSQL VARCHAR(max)
DECLARE curUpdates CURSOR FOR
-- field 1 is varchar(50), not null
-- field 2 is XML(.), null
SELECT
t.field1
,REPLACE(CAST(t.[field2] AS VARCHAR(max)), '''', '''''')
FROM
myTable t
WHERE
t.criteria = 0
OPEN curUpdates
FETCH NEXT FROM curUpdates INTO #field1Col, #field2Col
WHILE ##FETCH_STATUS = 0
BEGIN
SET #vsSQL = 'UPDATE dbo.myTable SET [field1] = ''' + #field1Col+ ''' WHERE [field2] = ''' + #field2Col + ''''
INSERT INTO #tmp ( SQLText ) VALUES ( #vsSQL )
FETCH NEXT FROM curUpdates INTO #field1Col, #field2Col
END
CLOSE curUpdates
DEALLOCATE curUpdates
SET NOCOUNT OFF;
SELECT * FROM #tmp
The issue I have is that even using VARCHAR(max), the XML will sometimes overrun the size. The end product just stops when it reaches the so many characters (the max size of a VARCHAR?).
Is there another approach for working with large XML (splitting into chunks, avoid casting, etc.) where I can build a string of update statements from it?
I do not have access to database B. I'd like to (one time run) update
a few tables in database B
The one time run could point to something like this:
CREATE DATABASE MyOneTimeRun;
GO
USE MyOneTimeRun;
GO
SELECT * INTO MyCopy FROM YourDatabase.dbo.YourTable;
GO
BACKUP DATABASE [MyOneTimeRun] TO DISK = N'C:\Path\MyOneTimeRun.bak' WITH NOFORMAT, NOINIT
,NAME = N'MyOneTimeRun-Copy of MyTable'
,SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
USE master;
GO
EXEC msdb.dbo.sp_delete_database_backuphistory #database_name = N'MyOneTimeRun'
GO
USE [master]
GO
ALTER DATABASE [MyOneTimeRun] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
USE [master]
GO
DROP DATABASE [MyOneTimeRun]
GO
Now you have a BAK-file with the content you need which you can restore on your other server.
There you use the appropriate scripts to shuffle your data typesafe and clean from the copy into your target.

Get the database name in which Stored Procedure exists

I am having SQL server 2008 and i am having 10 different databases in it and now i want to search one stored procedure that in which database the stored procedure is present.
Mentioned as duplicate by some ..... with out reading my question properly. My Requirement is i need to verify 'SP_Email' procedure. I which database is this procedure exists.
You can try this:
EXEC sp_msforeachdb
'if exists(select 1 from [?].sys.objects where name=''SP_Email'')
select ''?'' as FoundInDatabase from [?].sys.objects where name=''SP_Email'''
Please try this.
SELECT name DatabaseName
FROM sys.databases
WHERE OBJECT_ID(QUOTENAME(name) + '.dbo.ProcedureNameHere', 'P') IS NOT NULL;
This will return the database(s) name in which this particular object exist.
Replace ProcedureNameHere with your procedure name. In your case it would be SP_Email Keep rest of the things as it is.
you need to query sys.databases of master database to get list of databases and for each database name you get you need to query the db_name.sys.procedures to check if it exists.
try below query and give a feedback:
use master
go
declare #FullQuery varchar(max)
declare #DBName varchar(50)
set #FullQuery=''
declare cr cursor for select name from sys.databases where database_id > 4
open cr
fetch next from cr into #DBName
while(##fetch_status=0)
begin
set #FullQuery=#FullQuery+
' select name COLLATE SQL_Latin1_General_CP1_CI_AS from '+#DBName+'.sys.procedures where name like ''%proc_name%'' union'
fetch next from cr into #DBName
end
close cr
deallocate cr
set #FullQuery=substring(#FullQuery,1,len(#FullQuery)-5)
exec (#FullQuery)
SELECT OBJECT_ID('DataBase1.SchemaName.StoredProcedureName') /
OBJECT_ID('DataBase2.SchemaName.StoredProcedureName') /
OBJECT_ID('DataBase3.SchemaName.StoredProcedureName') /
...
It will return NULL if there is no such procedure. This will work if all databases are on same instance.

Resources