How to use backup with triggers in SQL Server 2008? - sql

I have a table (Cycle) and I created a trigger
alter trigger AnyName on Cycles
for insert,update,delete
AS
BACKUP DATABASE medrepcrm TO DISK = N'C:\medrepcrm.bak' WITH NOFORMAT, INIT, NAME = N'pcrm-Full Database Backup', SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
But when I insert, update, or delete in the Cycle table that leads to an error.
Msg 3021, Level 16, State 0, Procedure AnyName, Line 8
Cannot perform a backup or restore operation within a transaction.
Msg 3013, Level 16, State 1, Procedure AnyName, Line 8
BACKUP DATABASE is terminating abnormally.
The statement has been terminated.
What can I do to fix this error?

BACKUP DATABASE on MSDN says
The BACKUP statement is not allowed in an explicit or implicit transaction.
A trigger is always in a transactions
If you work it through, a backup which is transactionally consistent snapshot of a database: it doesn't make sense for it to be in it's own transaction.
Not least, on RESTORE the roll forward/roll back mechanism would have to rollback the transaction containing the backup... which defeats the purpose of the backup in the first place...

You could start a job sp_start_job. Within the job you execute a stored procedure where you execute the backup statement. I've done this already with a server trigger which is fired when a new database is created.

Related

Using sp_MSForEachTable to delete all data without filling up the transaction log

I have a database where I'd like to delete all data from all tables. The database is full of referential integrity (foreign keys, etc), so I can't use truncate - I have to use delete.
I found this script (source: https://stackoverflow.com/a/1899881/6647188):
USE [myDatabase]
GO
EXEC sp_MSForEachTable 'DISABLE TRIGGER ALL ON ?'
GO
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
GO
EXEC sp_MSForEachTable 'DELETE FROM ?'
GO
EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
GO
EXEC sp_MSForEachTable 'ENABLE TRIGGER ALL ON ?'
GO
However, the script fails w/ the following errors:
Msg 9002, Level 17, State 4, Line 7
The transaction log for database 'myDatabase' is full due to 'ACTIVE_TRANSACTION'.
Msg 9002, Level 17, State 4, Line 9
The transaction log for database 'myDatabase' is full due to 'ACTIVE_TRANSACTION'.
How can I rewrite the script to not fill up the transaction log? I've already tried restarting SSMS. Changing the log file to simple rather than full likely won't be easy since we don't have control of the log file (only DBA has access). However, I've looked into a concept called checkpoints, but am stuck.
Can someone alter this script so that it uses checkpoints to delete in batches then clears the log, rather than deleting it all in one go? Or provide another solution I haven't thought of?
provide another solution I haven't thought of?
Drop all the constraints and use TRUNCATE TABLE. Then the rows won't be logged, only the extent allocations. Or script out all the objects and create them in a new database.

SQL Server RESTORE VERIFY ONLY checks out but cannot RESTORE from backup

This is a real Hail Mary question because I am at a total loss. Using SQL Server 2017 Developer on Windows 10 x64. I have a backup file and run this command:
restore verifyonly from disk = 'f:\temp\northwind.bak';
It checks out as as a valid backup. But then I run this command:
restore database [northwind] from disk = 'f:\temp\northwind.bak' with replace;
It progresses to 100%, but just before completing I get this error message and the database goes into Recovery Pending:
Processed 348840 pages for database 'northwind', file 'Northwind' on
file 1. Processed 3 pages for database 'northwind', file
'Northwind_log' on file 1.
Msg 3167, Level 16, State 1, Line 12
RESTORE could not start database 'northwind'.
Msg 3013, Level 16, State 1, Line 12
RESTORE DATABASE is terminating abnormally.
Msg 5243, Level 22, State 8, Line 12
An inconsistency was detected during an internal operation.
How can the restore fail if it is supposedly a valid backup file? Any ideas what to look at?
In general database Recovery Pending means the database has encountered an internal error (i.e. lock/resources/physical files/transaction logs) which prevents it from bringing it online but not necessarily means it's impossible.
Could be that it couldn't unlock the physical files, could be a symptom of something else.
You can try turning it to online, and see if you get a better error message.
ALTER DATABASE [northwind] SET ONLINE
Or you can toggle emergency mode and run diagnostics through DBCC CHECKDB i.e.
ALTER DATABASE [northwind] SET EMERGENCY
GO
ALTER DATABASE [northwind] SET SINGLE_USER
GO
DBCC CHECKDB ([northwind]) WITH ALL_ERRORMSGS --Optionally run it like such DBCC CHECKDB ([northwind], REPAIR_ALLOW_DATA_LOSS)
GO
Further information:
Toggle DB State
Recovery Pending
DBCC CheckDB
Just run over http://www.edwinmsarmiento.com/the-scariest-lie-we-believed-about-backup-verification/
Could it be possible, that you made your backup without the CHECKSUM option? In this cases a RESTORE VERIFYONLY would not found page errors.

How to get the status of the backup database running through dynamic sql?

I have inherited a SQL Server job that runs a stored procedure which has dynamic SQL queries in it.
Example:
SET #statement = 'use master
ALTER DATABASE '+#database+' SET RECOVERY simple;
BACKUP DATABASE '+#database+'
TO DISK = ''xyz\'+#database+'.bak''
WITH INIT, COMPRESSION
WAITFOR DELAY ''00:00:10'';
ALTER DATABASE '+#database+'SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DROP DATABASE '+#database+';'
EXEC (#statement);
If I understand correctly, the waitfor delay was added to make sure that the backup is complete before altering the database. However, that is where I am getting confused.
My questions are:
Will the query jump to/execute Alter database command even when the backup transaction is in process?
How do I make the query wait until the backup is complete.
I tried to search resources to understand this but could not find any. Any help is appreciated. Thank you.
The execution is synchronous. No step in your execution will occur until the prior one is completed, so the WAITFOR will occur once the backup is completed and the second ALTER will occur after that.

why objectID(N'tablename') does not lock and name='tablename' does lock on sys.objects?

Experiment details:
I am running this in Microsoft SQL Server management studio.
On one query window I run:
BEGIN TRANSACTION a;
ALTER table <table name>
ALTER column <column> varchar(1025)
On the other I run:
SELECT 1
FROM sys.objects
WHERE name = ' <other_table name>'
Or this:
SELECT 1
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[<other_table name>]')
For some reason the select with name= does not return until I do commit to the tranaction.
I am doing transaction to simulate a long operation of alter column that we have in our DB sometimes. Which I don't want to harm other operations.
This is because you are working under Default Transaction Isolation Level i.e ReadCommited .
Read Commited
Under Read Commited Trasanction Isolation Level when you explicitly Begin a Transaction Sql Server obtains Exclusive locks on the resources in order to maintain data integrity and prevent users from dirty reads. Once you have begin a transaction and working with some rows other users will not be able to see them rows untill you Commit your transaction or Rollback. However this is sql server's default behaviour this can be changed under different Transaction Isolation Level for instance under Read Uncommited You will be able to read rows which are being Modified/Used by other users , but there is a chance of you have Dirty Reads "Data That you think is still in database but Other user has changed it."
My Suggestion
If Dirty Reads is something you can live with go on than
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITED;
Preferably Otherwise stick to default behaviour of Sql Server and let the user wait for a bit rather than giving them dirty/wrong data. I hope it helps.
Edit
it does not matter if the both queries are executed under same or different isolation level what matters is under what isolation level the queries are being executed, and you have to have Read Uncommited transaction isolation level when you are making use of explicit transactions. If you want other user to have access to the data in during a transaction. Not recomended and a bad practice, I would personally use Snapshot Isolation which will extensively make use of tempdb and will only show the last commited data.

ALTER DATABASE failed because a lock could not be placed on database

I need to restart a database because some processes are not working. My plan is to take it offline and back online again.
I am trying to do this in Sql Server Management Studio 2008:
use master;
go
alter database qcvalues
set single_user
with rollback immediate;
alter database qcvalues
set multi_user;
go
I am getting these errors:
Msg 5061, Level 16, State 1, Line 1
ALTER DATABASE failed because a lock could not be placed on database 'qcvalues'. Try again later.
Msg 5069, Level 16, State 1, Line 1
ALTER DATABASE statement failed.
Msg 5061, Level 16, State 1, Line 4
ALTER DATABASE failed because a lock could not be placed on database 'qcvalues'. Try again later.
Msg 5069, Level 16, State 1, Line 4
ALTER DATABASE statement failed.
What am I doing wrong?
After you get the error, run
EXEC sp_who2
Look for the database in the list. It's possible that a connection was not terminated. If you find any connections to the database, run
KILL <SPID>
where <SPID> is the SPID for the sessions that are connected to the database.
Try your script after all connections to the database are removed.
Unfortunately, I don't have a reason why you're seeing the problem, but here is a link that shows that the problem has occurred elsewhere.
http://www.geakeit.co.uk/2010/12/11/sql-take-offline-fails-alter-database-failed-because-a-lock-could-not-error-5061/
I managed to reproduce this error by doing the following.
Connection 1 (leave running for a couple of minutes)
CREATE DATABASE TESTING123
GO
USE TESTING123;
SELECT NEWID() AS X INTO FOO
FROM sys.objects s1,sys.objects s2,sys.objects s3,sys.objects s4 ,sys.objects s5 ,sys.objects s6
Connections 2 and 3
set lock_timeout 5;
ALTER DATABASE TESTING123 SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
Try this if it is "in transition" ...
http://learnmysql.blogspot.com/2012/05/database-is-in-transition-try-statement.html
USE master
GO
ALTER DATABASE <db_name>
SET OFFLINE WITH ROLLBACK IMMEDIATE
...
...
ALTER DATABASE <db_name> SET ONLINE
Just to add my two cents. I've put myself into the same situation, while searching the minimum required privileges of a db login to run successfully the statement:
ALTER DATABASE ... SET SINGLE_USER WITH ROLLBACK IMMEDIATE
It seems that the ALTER statement completes successfully, when executed with a sysadmin login, but it requires the connections cleanup part, when executed under a login which has "only" limited permissions like:
ALTER ANY DATABASE
P.S. I've spent hours trying to figure out why the "ALTER DATABASE.." does not work when executed under a login that has dbcreator role + ALTER ANY DATABASE privileges. Here's my MSDN thread!
I will add this here in case someone will be as lucky as me.
When reviewing the sp_who2 list of processes note the processes that run not only for the effected database but also for master. In my case the issue that was blocking the database was related to a stored procedure that started a xp_cmdshell.
Check if you have any processes in KILL/RollBack state for master database
SELECT *
FROM sys.sysprocesses
WHERE cmd = 'KILLED/ROLLBACK'
If you have the same issue, just the KILL command will probably not help.
You can restarted the SQL server, or better way is to find the cmd.exe under windows processes on SQL server OS and kill it.
In SQL Management Studio, go to Security -> Logins and double click your Login. Choose Server Roles from the left column, and verify that sysadmin is checked.
In my case, I was logged in on an account without that privilege.
HTH!
Killing the process ID worked nicely for me.
When running "EXEC sp_who2" Command over a new query window... and filter the results for the "busy" database , Killing the processes with "KILL " command managed to do the trick. After that all worked again.
I know this is an old post but I recently ran into a very similar problem. Unfortunately I wasn't able to use any of the alter database commands because an exclusive lock couldn't be placed. But I was never able to find an open connection to the db. I eventually had to forcefully delete the health state of the database to force it into a restoring state instead of in recovery.
In rare cases (e.g., after a heavy transaction is commited) a running CHECKPOINT system process holding a FILE lock on the database file prevents transition to MULTI_USER mode.
In my scenario, there was no process blocking the database under sp_who2. However, we discovered because the database is much larger than our other databases that pending processes were still running which is why the database under the availability group still displayed as red/offline after we tried to 'resume data'by right clicking the paused database.
To check if you still have processes running just execute this command:
select percent complete from sys.dm_exec_requests
where percent_complete > 0