From: Craig Lister on
Hi guys.

On a previous project, the requirement was just to store who updated a
row, and when. So, we have a:

created_date, created_user_id, modified_date and modified_user_id

However, phase 2 of this project - they want to know which fields in
the row were edited by which user! So, basically, per field auditing.
This is something I have never done. There's also two ways a field can
be updated. It can be updated by a user, or via an automated process,
at which point, a user should be stopped from editing it (client side
enforcement). So, I was thinking that we could make a nullable field
for the updated_user.. and if it's null, it was automated, and
therefore locked...

But.. this has to cover all the columns! It would be very messy to
have, for example, a 'description' field, and then a
'description_modified_date', and 'description_modified_user_id'....

I was thinking maybe a separate table that covered all tables and
columns that we need to log, and then a trigger to update these? But
am not sure if this is a good move, or the most effective way of
handling this requirement.

When we display the screen, it would be a hefty procedure to populate
the screen! We'd not only have to get the data, but then get all the
audit data - so that we can show the developer if the user can edit
the data or not.

Headache! Unless there is a way that this is done previously?
From: Uri Dimant on
Craig what versrion of SQL Server are you using?


"Craig Lister" <cdotlister(a)gmail.com> wrote in message
news:ad51480b-80ab-4859-8290-81d80aeffd19(a)x18g2000pro.googlegroups.com...
> Hi guys.
>
> On a previous project, the requirement was just to store who updated a
> row, and when. So, we have a:
>
> created_date, created_user_id, modified_date and modified_user_id
>
> However, phase 2 of this project - they want to know which fields in
> the row were edited by which user! So, basically, per field auditing.
> This is something I have never done. There's also two ways a field can
> be updated. It can be updated by a user, or via an automated process,
> at which point, a user should be stopped from editing it (client side
> enforcement). So, I was thinking that we could make a nullable field
> for the updated_user.. and if it's null, it was automated, and
> therefore locked...
>
> But.. this has to cover all the columns! It would be very messy to
> have, for example, a 'description' field, and then a
> 'description_modified_date', and 'description_modified_user_id'....
>
> I was thinking maybe a separate table that covered all tables and
> columns that we need to log, and then a trigger to update these? But
> am not sure if this is a good move, or the most effective way of
> handling this requirement.
>
> When we display the screen, it would be a hefty procedure to populate
> the screen! We'd not only have to get the data, but then get all the
> audit data - so that we can show the developer if the user can edit
> the data or not.
>
> Headache! Unless there is a way that this is done previously?


From: Erland Sommarskog on
Craig Lister (cdotlister(a)gmail.com) writes:
> On a previous project, the requirement was just to store who updated a
> row, and when. So, we have a:
>
> created_date, created_user_id, modified_date and modified_user_id
>
> However, phase 2 of this project - they want to know which fields in
> the row were edited by which user! So, basically, per field auditing.

If you are on SQL 2008 and have Enterprise Edition you could consider
using SQL Server Audit for the task.

Else a solution which is available with SQL 2005 and with any edition
is to use XML. Here is a quick example from a database that I have:

INSERT auditlog (tablename, keyvalue1,
action, beforeimage, afterimage)
SELECT 'accounts', coalesce(i.accno, d.accno),
CASE WHEN i.accno IS NULL THEN 'D'
WHEN d.accno IS NULL THEN 'I'
ELSE 'U'
END,
(SELECT * FROM deleted d2
WHERE d2.accno = i.accno FOR XML RAW, TYPE),
(SELECT * FROM inserted i2
WHERE i2.accno = i.accno FOR XML RAW, TYPE)
FROM inserted i
FULL JOIN deleted d ON i.accno = d.accno

As you can tell from the appearance of inserted/deleted, this is part
of a trigger. In this example, accno is the primary key of the table.

That is, in this table we store a copy of the row as it looked before and
after the update.

Currently we don't use this table for anything but manual investigations,
but an idea is to write a generic GUI which permits the user to browse
changes. The GUI would present the table names and the field names,
but only show the differences. It would may be not be the best user
experience, but it would be a lot easier to implement.

(In the example above, you don't see username, the time for the operation
etc. There are column for this in the table, but as they have default
values, you don't see them in the SELECT statement.)


> This is something I have never done. There's also two ways a field can
> be updated. It can be updated by a user, or via an automated process,
> at which point, a user should be stopped from editing it (client side
> enforcement). So, I was thinking that we could make a nullable field
> for the updated_user.. and if it's null, it was automated, and
> therefore locked...

This is certainly an extra challenge, and it does not sound like a
requirement that is particularly cheap to implement. You could
use the audit table to find out if the most recent change was
made by automatic user, but in the model above it's not easy to dig
out this information.

You should probably track this status separately from auditing. Maybe
a table keyed by tablename, keyvalue and column name. You add a row
when a column gets locked. But I cannot say that I like this terribly
much. Having metadata as data in the user tables is OK for auditing,
but when you use it for enforcing business rules, it's less appealing.
But the alternative is to have a "is_locked" column for every column
which is unpleasant as well.

Usually, these kind of ugly requirments tends to evaporate. If you
tell the people who decides that this requirement will cost an arm
and a leg to implment they may reconsider. Maybe locking is only needed
on row level?


--
Erland Sommarskog, SQL Server MVP, esquel(a)sommarskog.se

Links for SQL Server Books Online:
SQL 2008: http://msdn.microsoft.com/en-us/sqlserver/cc514207.aspx
SQL 2005: http://msdn.microsoft.com/en-us/sqlserver/bb895970.aspx
SQL 2000: http://www.microsoft.com/sql/prodinfo/previousversions/books.mspx

From: Jan Waiz on
Hi Craig,

if i understand you problem right, may be the OUTPUT clause will help you
tracking all that individual values.

USE AdventureWorks;
GO
DECLARE @MyTableVar table( ScrapReasonID smallint, Name varchar(50),
ModifiedDate datetime);

INSERT Production.ScrapReason
OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate INTO
@MyTableVar
VALUES (N'Operator error', GETDATE());

--Display the result set of the table variable.
SELECT ScrapReasonID, Name, ModifiedDate FROM @MyTableVar;
--Display the result set of the table.
SELECT ScrapReasonID, Name, ModifiedDate
FROM Production.ScrapReason;
GO

Above Example (from Help *s*) will show you how you can use it. In that
example only inserted rows and columns (!) are tracked in the temp-table.
You can use any other valid technic instead of a temp-table - but do so is
the most flexibal one. The OUTPUT-Clause will work on an UPDATE and DELETE
also.

And via SQL-Functions like SUSER_SNAME and/or SUSER_SID you can track
additional information about the current logged in user.

Try out and let me know if that helps

Regards
Jan Waiz

"Craig Lister" <cdotlister(a)gmail.com> schrieb im Newsbeitrag
news:ad51480b-80ab-4859-8290-81d80aeffd19(a)x18g2000pro.googlegroups.com...
> Hi guys.
>
> On a previous project, the requirement was just to store who updated a
> row, and when. So, we have a:
>
> created_date, created_user_id, modified_date and modified_user_id
>
> However, phase 2 of this project - they want to know which fields in
> the row were edited by which user! So, basically, per field auditing.
> This is something I have never done. There's also two ways a field can
> be updated. It can be updated by a user, or via an automated process,
> at which point, a user should be stopped from editing it (client side
> enforcement). So, I was thinking that we could make a nullable field
> for the updated_user.. and if it's null, it was automated, and
> therefore locked...
>
> But.. this has to cover all the columns! It would be very messy to
> have, for example, a 'description' field, and then a
> 'description_modified_date', and 'description_modified_user_id'....
>
> I was thinking maybe a separate table that covered all tables and
> columns that we need to log, and then a trigger to update these? But
> am not sure if this is a good move, or the most effective way of
> handling this requirement.
>
> When we display the screen, it would be a hefty procedure to populate
> the screen! We'd not only have to get the data, but then get all the
> audit data - so that we can show the developer if the user can edit
> the data or not.
>
> Headache! Unless there is a way that this is done previously?

From: Craig Lister on
On Jul 5, 2:46 pm, "Uri Dimant" <u...(a)iscar.co.il> wrote:
> Craig what versrion of SQL Server are  you using?

Microsoft SQL Server 2005 - 9.00.4226.00 (Intel X86)

Just reading the other replies.... thanks guys.
 |  Next  |  Last
Pages: 1 2
Prev: Maintenance scripts
Next: SQL Server cannot connect