views:

2376

answers:

10

How can I monitor a MSSQL database for changes to a table without using triggers or modifying the structure of the database in any way? My preferred programming environment is .Net and C#

(edits)

I'd like to support MS SQL 2000 SP4 or higher

by "changes to a table" I mean changes to table data, not changes to table structure.

Ultimately, I would like the change to trigger an event in my application, instead of having to check for changes at an interval.

+1  A: 

Why don't you want to use triggers. They are a good thing if you use them correctly. If you use them as a way to enforce referential integrity that is when they go from good to bad. But if you use them for monitoring, they are not really considered taboo.

Nick Berardi
A: 

I'd like to be able to support any MSSQL 2000 sp4 or newer. My application is a bolt-on data visualization for another company's product. Our customer base is in the thousands, so I don't want to have to put in requirements that we modify the third-party vendor's table at every installation.

TimM
+1  A: 

Have a DTS job (or a job that is started by a windows service) that runs at a given interval. Each time it is run, it gets information about the given table by using the system INFORMATION_SCHEMA tables, and records this data in the data repository. Compare the data returned regarding the structure of the table with the data returned the previous time. If it is different, then you know that the structure has changed.

Example query to return information regarding all of the columns in table ABC (ideally listing out just the columns from the INFORMATION_SCHEMA table that you want, instead of using select * like I do here):

select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'ABC'

You would monitor different columns and INFORMATION_SCHEMA views depending on how exactly you define "changes to a table".

Yaakov Ellis
+13  A: 

Take a look at the CHECKSUM command:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);

That will return the same number each time it's run as long as the table contents haven't changed. See my post on this for more information:

http://msdn.microsoft.com/en-us/library/aa258245(SQL.80).aspx

Here's how I used it to rebuild cache dependencies when tables changed: http://weblogs.asp.net/jgalloway/archive/2005/05/07/406056.aspx

Jon Galloway
+1  A: 

I can't understand one thing - do you want to monitor data changes or database structure changes?

Marek Grzenkowicz
+2  A: 

How often do you need to check for changes and how large (in terms of row size) are the tables in the database? If you use the CHECKSUM_AGG(BINARY_CHECKSUM(*)) method suggested by John, it will scan every row of the specified table. The NOLOCK hint helps, but on a large database, you are still hitting every row. You will also need to store the checksum for every row so that you tell one has changed.

Have you considered going at this from a different angle? If you do not want to modify the schema to add triggers, (which makes a sense, it's not your database), have you considered working with the application vendor that does make the database?

They could implement an API that provides a mechanism for notifying accessory apps that data has changed. It could be as simple as writing to a notification table that lists what table and which row were modified. That could be implemented through triggers or application code. From your side, ti wouldn't matter, your only concern would be scanning the notification table on a periodic basis. The performance hit on the database would be far less than scanning every row for changes.

The hard part would be convincing the application vendor to implement this feature. Since this can be handles entirely through SQL via triggers, you could do the bulk of the work for them by writing and testing the triggers and then bringing the code to the application vendor. By having the vendor support the triggers, it prevent the situation where your adding a trigger inadvertently replaces a trigger supplied by the vendor.

Chris Miller
A: 

Wild guess here: If you don't want to modify the third party's tables, Can you create a view and then put a trigger on that view?

Orion Edwards
+3  A: 

Unfortunately, I do not think that there is a clean way to do this in SQL2000. If you narrow your requirements to SQL2005+, then you are in business. You can use the SQLDependency class in System.Data.SqlClient. See http://msdn.microsoft.com/en-us/library/t9x04ed2.aspx

caryden
+4  A: 

Thanks for your feedback everyone. The best course of action given my requirements (no triggers or schema modification, MSSQL 2000 and 2005) seems to be to use the BINARY_CHECKSUM function in T-SQL. The way I plan to implement is this:

Every x seconds run the following query:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);

and compare that against the stored value. If the value has changed, go through the table row by row using the following query:

select row_id,BINARY_CHECKSUM(*) from sample_table WITH (NOLOCK);

and compare the returned checksums against stored values.

TimM
A: 

Thanks also to Caryden for your answer. Unfortunately, I can't require the customer to be on SQL 2005. Perhaps i can check for the SQL server version and use one method for SQL 2000 and the other for SQL 2005? That seems a little messy to me, but I'll try it out.

TimM