How to determine whether a database has been changed or not? - sql-server

I have a need to determine if a database on a MS SQL Server has changed between two distinct moments.
The change can be structural or data-related and the check should be generic (i.e. independant of the structure of the database).
Preferably, I'd like the check to be T-SQL based or with SMOs, not file based. I checked on MSDN but I haven't found anything relevant so far.

A possible solution for the scenario you described is to read the database transaction log (an LDF file). Any changes, both on schema or data level that were committed against the database are recorded in the database transaction log. Now, how to read the information that's in the t-log?
You can use either native SQL Server functions fn_dblog, DBCC PAGE or fn_dump_dblog or some 3rd party tool. However, the native functions are not documented and it's very hard to understand the results they provide. As for a 3rd party tool, you can check the Open LDF file and view LDF file content online article for more details and deeper analysis of what it takes to read the transaction log information
Disclaimer: I work as a Product Support Engineer at ApexSQL

For SQL Server 2005 and up you can add a DDL trigger, like:
CREATE TRIGGER [YourDatabaseTrigger]
ON DATABASE
FOR DDL_EVENTS
AS
DECLARE #EventData xml
DECLARE #Message varchar(1000)
SET #EventData=EVENTDATA()
INSERT INTO YourLogTable
(EventDateTime,EventDescription)
VALUES (GETDATE(),SUSER_NAME()
+'; '+#EventData.value('(/EVENT_INSTANCE/ObjectType)[1]', 'varchar(250)')
+'; '+#EventData.value('(/EVENT_INSTANCE/ObjectName)[1]', 'varchar(250)')
+'; '+#EventData.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
)
RETURN
GO
ENABLE TRIGGER [YourDatabaseTrigger] ON DATABASE
You would then need to create an triggers (for INSERT/UPDATE/DELETE) on each table in the database that would insert into the same table:
CREATE TRIGGER YourTableTrigger On YourTable
FOR INSERT
AS
INSERT INTO YourLogTable
(EventDateTime,EventDescription)
SELECT GETDATE(),SUSER_NAME()
+'; INSERT YourTable'+
+'; data='+...your column data here...
FROM INSERTED
GO

Red Gate make two products that might interest you:
SQL Compare
SQL Data Compare
They can compare the current version of the database with a backup copy and find changes in the schema or data respectively.

For structural changes, you probably might want to consider logging DDL events on your server by using DDL triggers or Service Broker. However, identifying data changes might be much more difficult to achieve unless you have something to compare to. I can think of Database Snapshot as a possible solution (requires Enterprise Edition).

Related

Log table Schema changes

Is there any way to log the changes made in Schema of a Table whenever I do the schema changes?
I was reading an article here about DDL Triggers. But it does not tell about the specific changes made in schema of a table.
this would be very difficult as quite often in SSMS the table is actually dropped and rebuilt in the background (depending on the complexity of the schema change & whether or not you enabled the "Prevent saving changes that require the table to be re-created " option in SSMS) - logging all the different types of changes would be a nightmare. (constraints being dropped, only to be re-created - bulk re-inserts, renames etc when all you might have done is re-arranged columns in joined table)
If you're serious about tracking schema changes i'd strongly recommend you script the schema (using the generate scripts option in MSSMS) & check the resulting file into SVN / SourceSafe / TFS & use the many comparison tools available for those systems.
OR, you can use 3rd party products that do all this for you, such as Red Gates SQL Source Control:
http://www.red-gate.com/products/sql-development/sql-source-control/
Edit: You may find this useful - it makes use of the Service Broker (SQL 2005+) and SSB queues:
http://www.mssqltips.com/sqlservertip/2121/event-notifications-in-sql-server-for-tracking-changes/
For this issue i would probably use Event Notifications. Although DDL trigger's in my opinion do tell about specific changes made to table, just trigger definition:
Create Trigger tr_DDLNotikums
On DataBase
For **DDL_DATABASE_LEVEL_EVENTS**
Use DDL Trigger In Below Format
CREATE TRIGGER tr_DDL_Database ON DATABASE
FOR DDL_SCHEMA_EVENTS
AS Begin
Insert Into LogTable (XmlColumn)
SELECT EVENTDATA()
End

regarding sql server transaction log

if some one delete any object from my database like table,view,sp etc then how can get those detail like who delete and when delete from transaction log. is it possible. please tell me easy way to read transaction log as a result i can get those detail properly.
thanks
No, ransaction log was created for different purposes. There are some product different vendors which is trying to get information from transaction log, but it is not right way.
who delete and when delete
If you need this information you need to create triggers to table for delete or update and collect this information.
If you use MS SQL 2008 you can use Change Data Capture feature.
Apparently you could use a third part product such as Apex SQL Log, although personally I have not used it.
Dependant on how recent the incident occured, you may also be able to extract the information you require from the built in reports in SQL Server 2005 such as the Schema Changes History Report. This information is accessable to you via means of the Default Trace. See using the Default Trace for details.
What you really need to take away from your incident is to use the lesson to devise a schema audit strategy for your environment. There are plenty of articles on the internet that detail how this can be achieved using Triggers. For example see Using DDL Triggers in SQL Server 2005 to Capture Schema Changes
You can restore the database (without overwriting it!) from a full backup / transaction log backup and then copy the deleted objects from there. It's good practice to save the source code for your stored procedures, views and tables outside the database, usually in a source control system, so you don't have to restore database backup to get them.
You can use either DDL triggers or The SQL Server Audit feature
DDL triggers fire on CREATE, ALTER, DROP, and operations related to database object security settings (e.g. GRANT, DENY…)
In the following example, a DDL trigger tracks the CREATE, ALTER, and DROP operations executed on database tables, stored procedures, functions, and views. The trigger example uses a previously created repository table (DDL_Events_by_DDL_TRIGGER) with appropriate rows
CREATE TRIGGER DDL_TRIGGER ON DATABASE
FOR CREATE_TABLE ,
ALTER_TABLE ,
DROP_TABLE ,
CREATE_PROCEDURE ,
ALTER_PROCEDURE ,
DROP_PROCEDURE ,
CREATE_FUNCTION ,
ALTER_FUNCTION ,
DROP_FUNCTION ,
CREATE_VIEW ,
ALTER_VIEW ,
DROP_VIEW
AS
DECLARE
#event xml;
SET
#event = EVENTDATA();
INSERT INTO DDL_Events_by_DDL_TRIGGER
VALUES
(
REPLACE(CONVERT(varchar(58),
#event.query('data(/EVENT_INSTANCE/PostTime)')), 'T', ' ')
,
CONVERT(varchar(185),
#event.query('data(/EVENT_INSTANCE/LoginName)'))
,
CONVERT(varchar(185),
#event.query('data(/EVENT_INSTANCE/DatabaseName)'))
,
CONVERT(varchar(185),
#event.query('data(/EVENT_INSTANCE/SchemaName)'))
,
CONVERT(varchar(185),
#event.query('data(/EVENT_INSTANCE/ObjectName)'))
,
CONVERT(varchar(185),
#event.query('data(/EVENT_INSTANCE/ObjectType)'))
,
CONVERT(varchar(max),
#event.query('data(/EVENT_INSTANCE/TSQLCommand/CommandText)'))
);
The repository table will contain (as specified in the trigger) DDL operations on the database schema, along with information about who, when, and what was altered
Another native method that can be used to determine whether a SQL Server database has been altered is the SQL Server Audit feature. The feature was introduced in SQL Server 2008 and it collects both server and database level actions raised by the SQL Server Extended Events feature. However, the database level action groups are available in SQL Server Enterprise and Developer editions only

Database availability during database update

I have a database from a 3rd party. They supply a tool to update the database data weekly. The tool is pretty old and uses ODBC. Updates can either be incremental or can delete all database data then recreate the data. The update can take several hours. In order to have high availability, it was suggested to have 2 SQL databases, and store a "active database" setting in another database to determine which of the two databases applications should use (while the other could be being updated).
One issue we are running into is: How to do reference the active database in stored procedures in other databases?
Is this the right approach? Is there a simple, perhaps-infrastructure-based approach? (Should this be posted on ServerFault?)
Note: Databases are read-only besides the update tool.
If the databases are on different servers, you can create an alias for the server which will redirect to the other server in SQL Server Configuration Manager. Under SQLNative Client 10.0 Configuration (or 9.0 if you're in SQL Server 2005) you can add a new alias.
Otherwise, you can always rename the databases using sp_dbrename so thata your client applications are always using database1 while you are updating database2.
If you want to use different databases inside a stored procedure you either need to:
Duplicate all the calls. Ugly. You would end with a lot of:
if #firstDatabase=1
select * from database1..ExampleTable where ...
else
select * from database2..ExampleTable where ...
Use dynamic queries. Less ugly:
set #sqlQuery='select * from '+#currentDatabase+'..ExampleTable where...'
exec sp_executesql #sqlQuery
I admit that neither solution is perfect...
I'd take the approach of having the stored procedures in both databases with some sort of automatic trigger to update the stored procedures in the other database if a stored procedure is changed.

SSIS - Log to table other than SYSSSISLOG

SSIS seems to insist on logging to the system table SYSSSISLOG. Is there a way to make it use a different table?
I want each package to log to a different table.
Quick answer is the same as John Sansom's answer: When logging is used, it creates a table and a stored proc (name varies with version between 2005 and 2008) The stored proc can be modified to do whatever you want. If the stored proc is removed Sql server re-creates it, but if the stored proc is there, Sql server assumes it is OK and leaves it alone. This allows you to modify the stored proc to write to whatever table/tables you want.
Well, you can query that huge-ass log table with something like this:
--first, we identify the packages
;with DetectedPackages as (
select source, s.executionid
from dbo.sysssislog as s
where event = 'PackageStart'
group by source, s.executionid
)
--then we use those executionids to display results
select * from dbo.sysssislog as s
join DetectedPackages dp on s.executionid = dp.executionid
where dp.source = 'PackageName'
And if you want to encapsulate every package in a view, now you know how to do that.
Take a look at the following article over on SQL Server Central, you may need to register but it's free to do so and you will find the site to be excellent SQL Server resource.
The article details how to implement a custom Log Provider that redirects the SSIS log output to another table. Using this implementation as your framework you could extend it to meet your requirements.
SSIS Custom Logging the Easy Way
The above is quite correct however not written well. When you specify your logging in SSIS you can log to a specific data provider IE SSIS Log provider for SQL Server. When you point this to a specific database it will create a [dbo].[sysssislog] table under the System Tables folder in your database. If you navigate in SSMS to your database and programmability -> Stored Procedures there will be a procedure called [dbo].[sp_ssis_addlogentry] this will insert log entries from SSIS. You can repoint this stored procedure to point to the table you want to log to instead of the one generated by SSIS within your database.

SQL Server replication without deletes?

Is there a way to replicate a sql server database but not push out deletes to the subscribers?
You don't mention which version of SQL Server you're running, but Andy Warren wrote an article on configuring INSERT, UPDATE, and DELETE behaviour in SQL Server 2005. You can configure this through the GUI, using his instructions:
http://www.sqlservercentral.com/articles/Replication/3202/
It's tempting to 'intervene' in a normal replication and 'disarm' the subscriber's side delete stored procedures, but this leaves no option to recover from replication failure. If the replication tries to recover, a reinitialize may be needed and this will drop any 'stale' data that the replication agent considers deleted.
An alternative is to use a normal replication, and use a script that generates insert and update triggers on all tables in the subscriber database, that insert/update that data into yet a third database. This way the third DB will collect all the data that ever existed, the second DB can re-initialize it's subscription if it needs to (when you do, just remember that bulk inserts don't call the insert trigger and check for new data and add it to the third DB), and the first DB doesn't have to perform the extra work that the triggers are.
Do this....Drop the article. Create a new storedprocedure in the corresponding database that mimicks the system store procedure (sp_del...) and contains the same parameter but does nothing. Add the article again...and set the delete store procedure under the article's properties to the new delete stored procedure that you created....
Or you can select Do not replicate Delete Statements....I think that works but i haven't tried it.

Resources