Showing posts with label trigger. Show all posts
Showing posts with label trigger. Show all posts

Tuesday, March 27, 2012

Auto Create trigger after re-initialization completed

Hi all,

Is it possible to create a trigger after creation of table during reinitialization? if so, how can I do that? Thanks in advance!

Hi, Stephanie,

If I understand your question correctly, you wan to create a trigger on subscriber db right after replication agent created replicating table on subscriber database. If so, you can use post snapshot script.

To specify a post snapshot script in Management Studio, right click a publication under replication node, choose Properties context menu to bring up Publication Properties dialog, on the left pane treeview, click snapshot, you should see the input field to specify Pre snapshot script and post snapshot script under "Run Additional scripts" section.

Hope that helps,

Zhiqiang

This posting is provided "AS IS" with no warranties, and confers no rights.

|||

Thx for reply

I can't find the option 'After applying the snapshot, execute
this script text box' in Snapshot page of the Publication Properties as
stated in Online Books. Also, I found a note in online book stating 'These
options are not available if the Snapshot format option is set to Character.'

The replication from oracle to MSSQL2005 and the snapshot format is set to 'character' automatically. Is it possible to create trigger in such case? Thanks in advance

|||

Stephanie,

You're right, for snapshot using Character mode, the "run additional scripts" option is not available under Publication Properties dialog (disabled in the UI).

In this case, you can add an extra step to create your subscriber table trigger after the distribution or merge agent step in your synchronization job. Following are the steps:

1. Find your sync job under Management Studio --> Object Explorer --> SQL Server Agent --> Jobs --> Your distribution/merge agent job name

2. Right click the sync job, pick Properties from context menu, this will bring up Job Properties dialog

3. On the left side pane under "Select a page", click Steps

4. Insert a new step right after step "Run Agent" to execute your script to create the subscriber table trigger,

Example:

step name: Run Post snapshot script to create subscriber table trigger

type: Operating System (cmdexec)

RunAs: SQL Server Agent Service Account

Command: sqlcmd.exe -E -Ssubscriberinstancename -dsubscriberdbname -Q"create trigger postsnapshottrigger on [subscriberdbname].[dbo].[subscribertable] for update,insert,delete AS select * from sys.databases"

5. Change the Advanced Option for the new step:

On Success action: Quit the job reporting success

On failure action: Go to the next step

6. Change the Advanced Option for step "Run Agent":

On success action: Go to the next step

Leave on failure action unchanged

The original setting for "On success action" is "quite the job reporting success", this will result in the new step you just added being ignored thus we need this change.

7. Reinitialize your subscription and rerun your sync job

I have tested this scenario on a character mode merge publication and it worked just fine (I'm not using Oracle in this test).

If you're not using SQL Server agent to run your jobs, for example, using a batch file to run sync command directly, you can just add the command to create trigger after sync command.

Let me know if this helps.

Zhiqiang Feng

This posting is provided "AS IS" with no warranties, and confers no rights.

|||

The table is re-created after re-initialize but the trigger didn't be created. I found that the agent job is keeping 'running'...

Just want to confirm that the distribution job with the 1step 'Distribution agent startup message' , right?

Thanks in advance

|||

Hi, stephanie,

I just realized there is one issue with my approach if your distribution agent is set to run continuously (there is a -continuous prameter for the distribution command for step Run Agent), this way your new step will never get a chance to run since the Run Agent step is running continuously.

If your oracle publication can be re-created, you can walk through the New Oracle Publication Wizard and at the page of "Wizard Actions", uncheck "Create the publication" option and check "Generate a script file with steps to create the publication", once the script is created, modify the @.post_snapshot_script pointing to the location of your script to create the trigger, then run this generated script to create your oracle publication.

If you don't want to re-create your oracle publication, you can modify the generated snapshot files to create the trigger after the subscriber table is created (there should be a .sch file for your replicating table), then re-initialize your publication. Note this manual step need to be done each time you re-generated the snapshot files

You can also create a new SQL Server agent job to just create the trigger and have it to run continuously. The logic of your script should be: if subscriber table exist and if the trigger doesn't exist, then create the trigger. This will have some system overhead and your trigger may miss some transactions if updates to the table occurred and before the trigger is created.

Let me know if it helps.

Zhiqiang Feng

This posting is provided "AS IS" with no warranties, and confers no rights.

|||

I prefer option 1 but i found that there is no '@.post_snapshot_script ' in the scripted generated... should I append this option into the script? Also, there are 3 parts in the script, running

sys.sp_addlogreader_agent, exec sp_addpublication,
exec sp_addpublication_snapshot and sp_addarticle

where should I append it? Thanks in advance.

|||

@.post_snapshot_script is a parameter of sp_addpublication so it should be appended to the sp_addpublication call, see Books Online help topic for sp_addpublication for details of this parameter.

Let me know if you encounter any issues.

Zhiqiang Feng

This posting is provided "AS IS" with no warranties, and confers no rights.

|||Thanks a lot, it perfectly solve our problem! |||

That's great!

By the way, I've submitted a feature request to have new publication wizard support the addition of pre/post snapshot script, this issue may be addressed in a future release of SQL Server so you configure pre/post snapshot script without needing the manual step of modifying and running the replication script as a workaround.

Zhiqiang Feng

This posting is provided "AS IS" with no warranties, and confers no rights.

Auto Create trigger after re-initialization completed

Is it possible to create a trigger after creation of table during
reinitialization? if so, how can I do that? Thanks in advance!
Do it through a post snapshot command.
Hilary Cotter
Looking for a SQL Server replication book?
http://www.nwsu.com/0974973602.html
Looking for a FAQ on Indexing Services/SQL FTS
http://www.indexserverfaq.com
"stephanie" <stephanie@.discussions.microsoft.com> wrote in message
news:C8C2E193-7228-4A86-8E30-A6523CF62EFA@.microsoft.com...
> Is it possible to create a trigger after creation of table during
> reinitialization? if so, how can I do that? Thanks in advance!
>
|||What about if the replication from oracle to MSSQL2005 and the snapshot
format is set to 'character'? Thanks in advance.
"Hilary Cotter" wrote:

> Do it through a post snapshot command.
> --
> Hilary Cotter
> Looking for a SQL Server replication book?
> http://www.nwsu.com/0974973602.html
> Looking for a FAQ on Indexing Services/SQL FTS
> http://www.indexserverfaq.com
> "stephanie" <stephanie@.discussions.microsoft.com> wrote in message
> news:C8C2E193-7228-4A86-8E30-A6523CF62EFA@.microsoft.com...
>
>
|||A character format for the snapshot refers to the data.
A post snapshot command is a script file that you specify. Once the
snapshot completes, SQL Server will open the script file that you specify
and execute anything in the script.
Mike
Mentor
Solid Quality Learning
http://www.solidqualitylearning.com
"stephanie" <stephanie@.discussions.microsoft.com> wrote in message
news:A5E40A16-E2EF-4339-9F4E-D005820DEE45@.microsoft.com...[vbcol=seagreen]
> What about if the replication from oracle to MSSQL2005 and the snapshot
> format is set to 'character'? Thanks in advance.
> "Hilary Cotter" wrote:
|||Thx for reply. I can't find the option 'After applying the snapshot, execute
this script text box' in Snapshot page of the Publication Properties as
stated in Online Books. Also, I found a note in online book stating 'These
options are not available if the Snapshot format option is set to Character.'
ms-help://MS.SQLCC.v9/MS.SQLSVR.v9.en/rpldata9/html/b7bb1e4c-5b48-4bb1-9dc8-47c911f2cc82.htm
Please advise. Thanks
"Michael Hotek" wrote:

> A character format for the snapshot refers to the data.
> A post snapshot command is a script file that you specify. Once the
> snapshot completes, SQL Server will open the script file that you specify
> and execute anything in the script.
> --
> Mike
> Mentor
> Solid Quality Learning
> http://www.solidqualitylearning.com
>
> "stephanie" <stephanie@.discussions.microsoft.com> wrote in message
> news:A5E40A16-E2EF-4339-9F4E-D005820DEE45@.microsoft.com...
>
>
|||Forgot about that restriction. There was a reason for that restriction, but
I can't remember what it was right now.
One workaround is to create a DDL trigger like the following:
create trigger test
on database
for create_table
as
declare @.parentid int
select @.parentid = object_id from sys.tables where name = 'MyTable'
print @.parentid
if @.parentid is null
return
if exists (select 1 from sys.triggers where parent_id = @.parentid
and name = 'MyTestTrigger')
return
exec sp_executesql N'create trigger MyTestTrigger on MyTable for insert as
raiserror(''Test'',16,10)'
go
create table MyTable
(id int)
go
I can't think of any other workarounds at the moment.
Mike
Mentor
Solid Quality Learning
http://www.solidqualitylearning.com
"stephanie" <stephanie@.discussions.microsoft.com> wrote in message
news:2343A716-0B57-4972-A9B2-C3B4FECA72D9@.microsoft.com...[vbcol=seagreen]
> Thx for reply. I can't find the option 'After applying the snapshot,
> execute
> this script text box' in Snapshot page of the Publication Properties as
> stated in Online Books. Also, I found a note in online book stating
> 'These
> options are not available if the Snapshot format option is set to
> Character.'
> ms-help://MS.SQLCC.v9/MS.SQLSVR.v9.en/rpldata9/html/b7bb1e4c-5b48-4bb1-9dc8-47c911f2cc82.htm
> Please advise. Thanks
> "Michael Hotek" wrote:

Monday, March 19, 2012

Auditing tables

Hi ,
I am trying trigger for after delete /insert and update .
using below trigger , unable to insert data in myaudittable ..
Pls suggest , what changes should I make ?
Regards
"swati" <swati.zingade@.ugamsolutions.com> wrote in message news:...
> Thanks!! It works properly .
>
> Regards,
> Swati
>
> "Uri Dimant" <urid@.iscar.co.il> wrote in message
> news:ebvGMQ1uEHA.4084@.TK2MSFTNGP10.phx.gbl...
> > swati
> > create trigger tru_MyTable on MyTable after update
> > as
> >
> > if @.@.ROWCOUNT = 0
> > return
> >
> > insert MyAuditTable
> > select
> > i.ID
> > , d.MyColumn
> > , i.MyColumn
> > from
> > inserted i
> > join
> > deleted d on d.ID = o.Id
> > go
> >
> > "swati" <swati.zingade@.ugamsolutions.com> wrote in message
> > news:uNbsEK1uEHA.1308@.TK2MSFTNGP09.phx.gbl...
> > > HI!
> > >
> > > I want to audit some collumns of one of my huge table . I wrote a
> trigger
> > > for copying updated data and original data in audit table.
> > > But when I try to update multiple rows , it gives error of "cannot
> > update
> > > multiple rows. "
> > >
> > > Is there any easy way of auditing tables without using triggers . I
> donot
> > > want to use C2-audit .
> > >
> > > Regards,
> > > Swati
> > >
> > >
> > >
> > >
> > >
> >
> >
>
>What error are you getting? Please post your actual trigger code and table
DDL.
--
Hope this helps.
Dan Guzman
SQL Server MVP
"swati" <swati.zingade@.ugamsolutions.com> wrote in message
news:O$InOPAvEHA.1520@.TK2MSFTNGP11.phx.gbl...
> Hi ,
> I am trying trigger for after delete /insert and update .
> using below trigger , unable to insert data in myaudittable ..
> Pls suggest , what changes should I make ?
> Regards
>
> "swati" <swati.zingade@.ugamsolutions.com> wrote in message news:...
>> Thanks!! It works properly .
>> Regards,
>> Swati
>> "Uri Dimant" <urid@.iscar.co.il> wrote in message
>> news:ebvGMQ1uEHA.4084@.TK2MSFTNGP10.phx.gbl...
>> > swati
>> > create trigger tru_MyTable on MyTable after update
>> > as
>> >
>> > if @.@.ROWCOUNT = 0
>> > return
>> >
>> > insert MyAuditTable
>> > select
>> > i.ID
>> > , d.MyColumn
>> > , i.MyColumn
>> > from
>> > inserted i
>> > join
>> > deleted d on d.ID = o.Id
>> > go
>> >
>> > "swati" <swati.zingade@.ugamsolutions.com> wrote in message
>> > news:uNbsEK1uEHA.1308@.TK2MSFTNGP09.phx.gbl...
>> > > HI!
>> > >
>> > > I want to audit some collumns of one of my huge table . I wrote a
>> trigger
>> > > for copying updated data and original data in audit table.
>> > > But when I try to update multiple rows , it gives error of "cannot
>> > update
>> > > multiple rows. "
>> > >
>> > > Is there any easy way of auditing tables without using triggers . I
>> donot
>> > > want to use C2-audit .
>> > >
>> > > Regards,
>> > > Swati
>> > >
>> > >
>> > >
>> > >
>> > >
>> >
>> >
>>
>|||Thanks dan . There was some silly mistake I did in coding . Instead of using
full outer joins ,I was using normal joins ,so was not able to get the
deleted records .Now it's working fine.
regards,
Swati.
"Dan Guzman" <guzmanda@.nospam-online.sbcglobal.net> wrote in message
news:ulLkEBCvEHA.2196@.TK2MSFTNGP14.phx.gbl...
> What error are you getting? Please post your actual trigger code and
table
> DDL.
> --
> Hope this helps.
> Dan Guzman
> SQL Server MVP
> "swati" <swati.zingade@.ugamsolutions.com> wrote in message
> news:O$InOPAvEHA.1520@.TK2MSFTNGP11.phx.gbl...
> > Hi ,
> > I am trying trigger for after delete /insert and update .
> > using below trigger , unable to insert data in myaudittable ..
> > Pls suggest , what changes should I make ?
> >
> > Regards
> >
> >
> > "swati" <swati.zingade@.ugamsolutions.com> wrote in message news:...
> >> Thanks!! It works properly .
> >>
> >> Regards,
> >> Swati
> >>
> >> "Uri Dimant" <urid@.iscar.co.il> wrote in message
> >> news:ebvGMQ1uEHA.4084@.TK2MSFTNGP10.phx.gbl...
> >> > swati
> >> > create trigger tru_MyTable on MyTable after update
> >> > as
> >> >
> >> > if @.@.ROWCOUNT = 0
> >> > return
> >> >
> >> > insert MyAuditTable
> >> > select
> >> > i.ID
> >> > , d.MyColumn
> >> > , i.MyColumn
> >> > from
> >> > inserted i
> >> > join
> >> > deleted d on d.ID = o.Id
> >> > go
> >> >
> >> > "swati" <swati.zingade@.ugamsolutions.com> wrote in message
> >> > news:uNbsEK1uEHA.1308@.TK2MSFTNGP09.phx.gbl...
> >> > > HI!
> >> > >
> >> > > I want to audit some collumns of one of my huge table . I wrote a
> >> trigger
> >> > > for copying updated data and original data in audit table.
> >> > > But when I try to update multiple rows , it gives error of
"cannot
> >> > update
> >> > > multiple rows. "
> >> > >
> >> > > Is there any easy way of auditing tables without using triggers . I
> >> donot
> >> > > want to use C2-audit .
> >> > >
> >> > > Regards,
> >> > > Swati
> >> > >
> >> > >
> >> > >
> >> > >
> >> > >
> >> >
> >> >
> >>
> >>
> >
> >
>

Sunday, March 11, 2012

Auditing Status of a Trigger in SQL Server 2005

I need to know when a DML trigger changes state (from enabled to disabled, and disabled to enabled).

I **assume** this info is not in any of the standard SQL Server 2005 loags and find no entry relating to triggers being enabled/disabled.

Therefore I also *assume* the best way to do this is create a DDL Trigger and populate a table when a trigger status is changed.

Am I on the right track?

Has anyone done this? Code samples/links to solution?

Is there a simplier way <i'm all about simple>?

Thanks in advance.

Thats exactly the right direction, if you need a quikc sample for using DDL events, take a look at the DDL event definition in the BOL and perhpas at the slightly different samples on my website: http://sqlserver2005.de/articles/2/

HTH, Jens K. Suessmeyer.

http://www.sqlserver2005.de

Auditing and IP addresses

In a database I created an audit table in which, e.g., I insert one record
for each INSERT statement made on another table (via a trigger).
My problem is to recover remote IP address of the connected client which
does the INSERT.
I tried to use DMV sys.dm_exec_connections because it contains a "client_net_address"
field: it was just what was searching for.
But, unfortunately, this DMV requires VIEW SERVER STATE permission, which
is not assigned to any user.
May you tell me how can I solve this problem, avoiding to assign that permission
to everybody?
Thanks all.
PBsoft di Gabriele Bertolucci
www.pbsoft.it
skype:pbsoftsolution
Hi,
this is the only way to get the information. prior to the DMV you had
to retrieve the information from XP_cmdshell:
http://www.sqlserver2005.de/Articles/3/
HTH, Jens K. Suessmeyer.
http://www.sqlserver2005.de

Auditing and IP addresses

In a database I created an audit table in which, e.g., I insert one record
for each INSERT statement made on another table (via a trigger).
My problem is to recover remote IP address of the connected client which
does the INSERT.
I tried to use DMV sys.dm_exec_connections because it contains a "client_net_address"
field: it was just what was searching for.
But, unfortunately, this DMV requires VIEW SERVER STATE permission, which
is not assigned to any user.
May you tell me how can I solve this problem, avoiding to assign that permission
to everybody?
Thanks all.
--
PBsoft di Gabriele Bertolucci
www.pbsoft.it
skype:pbsoftsolutionHi,
this is the only way to get the information. prior to the DMV you had
to retrieve the information from XP_cmdshell:
http://www.sqlserver2005.de/Articles/3/
HTH, Jens K. Suessmeyer.
http://www.sqlserver2005.de
--

Thursday, March 8, 2012

Auditing and IP addresses

In a database I created an audit table in which, e.g., I insert one record
for each INSERT statement made on another table (via a trigger).
My problem is to recover remote IP address of the connected client which
does the INSERT.
I tried to use DMV sys.dm_exec_connections because it contains a "client_net
_address"
field: it was just what was searching for.
But, unfortunately, this DMV requires VIEW SERVER STATE permission, which
is not assigned to any user.
May you tell me how can I solve this problem, avoiding to assign that permis
sion
to everybody?
Thanks all.
PBsoft di Gabriele Bertolucci
www.pbsoft.it
skype:pbsoftsolutionHi,
this is the only way to get the information. prior to the DMV you had
to retrieve the information from XP_cmdshell:
http://www.sqlserver2005.de/Articles/3/
HTH, Jens K. Suessmeyer.
http://www.sqlserver2005.de
--

Auditing and IP addresses

In a database I created an audit table in which, e.g., I insert one record
for each INSERT statement made on another table (via a trigger).
My problem is to recover remote IP address of the connected client which
does the INSERT.
I tried to use DMV sys.dm_exec_connections because it contains a "client_net
_address"
field: it was just what was searching for.
But, unfortunately, this DMV requires VIEW SERVER STATE permission, which
is not assigned to any user.
May you tell me how can I solve this problem, avoiding to assign that permis
sion
to everybody?
Thanks all.
PBsoft di Gabriele Bertolucci
www.pbsoft.it
skype:pbsoftsolutionHi,
this is the only way to get the information. prior to the DMV you had
to retrieve the information from XP_cmdshell:
http://www.sqlserver2005.de/Articles/3/
HTH, Jens K. Suessmeyer.
http://www.sqlserver2005.de
--|||PBsoft (info[REMOVE]@.pbsoft.it) writes:
> In a database I created an audit table in which, e.g., I insert one record
> for each INSERT statement made on another table (via a trigger).
> My problem is to recover remote IP address of the connected client which
> does the INSERT.
> I tried to use DMV sys.dm_exec_connections because it contains a
> "client_net_address"
> field: it was just what was searching for.
> But, unfortunately, this DMV requires VIEW SERVER STATE permission, which
> is not assigned to any user.
> May you tell me how can I solve this problem, avoiding to assign that
> permission to everybody?
Create a certificate and which you sign the trigger with. You need to
have this certificate in master as well. Then create a login from that
certificate, and grant that login the rights.
I have an article on my web site that describes this in a lot more
detail: http://www.sommarskog.se/grantperm.html.
Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se
Books Online for SQL Server 2005 at
http://www.microsoft.com/technet/pr...oads/books.mspx
Books Online for SQL Server 2000 at
http://www.microsoft.com/sql/prodin...ions/books.mspx|||try the auditdatabase
auditing tools ( http://www.auditdatabase.com/AuditTools.html ) for
generate audit triggers (FREE) for SQL Server and other DBMS's)
This triggers save the client IP and MAC information
Delia.
Erland Sommarskog ha escrito:
> PBsoft (info[REMOVE]@.pbsoft.it) writes:
> Create a certificate and which you sign the trigger with. You need to
> have this certificate in master as well. Then create a login from that
> certificate, and grant that login the rights.
> I have an article on my web site that describes this in a lot more
> detail: http://www.sommarskog.se/grantperm.html.
>
> --
> Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se
> Books Online for SQL Server 2005 at
> http://www.microsoft.com/technet/pr...oads/books.mspx
> Books Online for SQL Server 2000 at
> http://www.microsoft.com/sql/prodin...ions/books.mspx

Audit Triggers SQL 2000

In the past I have used a poor mans audit trigger for my SQL tables. I basically created another identical table with "_Audit" at the end of it with the same fields. I simply did a trigger like this to copy the entire contents of the Row being updated, deleted, or Inserted.

CREATE TRIGGER fileAudit ON [dbo].[Table1]
FOR INSERT, UPDATE, DELETE
AS
insert Table1_audit
select
*
from inserted i
return

This is bad in several ways and I know that, but it was giving me Audit history that was better than nothing. The one thing I hate most about the above approach is that it copies the enitre record set even if only one field was updated or deleted and the fact I have an audit table for every table in the database.

I want to enhance my Audit Trail to include only one Audit_Table. I would like to mimic this approach that is using CLR for SQL 2005. My Only problem is I am forced to use SQL 2000 for legacy application on the database server. I do not have the ability to migrate to SQL 2005 at this time.

http://sqljunkies.com/Article/4CD01686-5178-490C-A90A-5AEEF5E35915.scuk

All of my Tables have an Auto-increment PK

Could some one point me in the right way to accomplish this.

I recommend to use the following structure;

TableName NVarchar(1000)

OperationDateTime DateTime

Operation smallint (1-Insert, 2-Update, 3-Delete)

Data Text (Common Delimited or XML value of the affected row)

The real challenge here is getting back – querying - the data. For that probably you can design your own UI where you can parse these values for display.

But again these audit trail operations are additional overhead on your data manipulation.

|||

TableName NVarchar(1000)

OperationDateTime DateTime

Operation smallint (1-Insert, 2-Update, 3-Delete)

Data Text (Common Delimited or XML value of the affected row)


Structure should depends on the purposes of audit. Because using this structure it is possible that you could never answer the question who changed some order or what have done John with another orders.
|||

don't use the '*' for auditting or you have to be very carefull of the datatype. you can't read timestamps, text, ... columns from the virtual inserted and deleted tables...

regards

skafever

Audit trigger with dynamic SQL and Cursor - Am I close?

Server = SQL Server 2000 SP3a
Client = Access 2000 SP3 (.adp)
Hi, can anyone advise me on creating an audit process to account for any
changes in a table, I thought I'd come up with quite a good idea and started
to do it, but now Im stuck. There are several tables which have 20-40
columns each, the plan was to create an audit table with:
CREATE TABLE [dbo].[tbl_Audit] (
[A_TABLE] [varchar] (50) NOT NULL,
[A_YEAR] [char] (4) NOT NULL ,
[A_VERSION] [varchar] (10) NOT NULL ,
[A_COST_CENTRE] [varchar] (6) NOT NULL ,
[A_ACCOUNT] [varchar] (8) NOT NULL ,
[A_COLUMN] [varchar] (50) NOT NULL ,
[A_OLD_VALUE] [varchar] (1000) NOT NULL ,
[A_NEW_VALUE] [varchar] (1000) NOT NULL ,
[A_DATE] [datetime] NULL ,
[A_USER] [varchar] (50) NULL
) ON [PRIMARY]
GO
This could then be used as a generic audit table, as the table is logged,
the identifying rows are logged (year, version, cost_centre, account), then
the column name, its old and new values.
This was going to be populated by a trigger which fired after an update, it
would loop though the column names and check the values from the inserted
table to the actual table to see if they were different, if they were
different then insert into audit.
I had started to write the trigger, but hit a problem early on, which is I'd
like to create one trigger which fits all tables with only minor tweaking, s
o
I thought I'd use a cursor to loop through the column names, but this means
(I think) using a dynamic sql string, but this seems to fail as the inserted
table goes out of scope, eg when the trigger below fires, it errors with:
Server: Msg 208, Level 16, State 1, Line 2
Invalid object name 'inserted'.
This I assume is because the inserted table is not in scope of the dynamic
SQL string @.SQL1 (below)
alter trigger tg_Estimates_Audit_Update
on dbo.tbl_estimates
after update
as
SET NOCOUNT ON
SET ANSI_NULLS ON
SET ANSI_WARNINGS ON
declare
@.COLUMN varchar(50),
@.SQL1 nvarchar(750),
@.USER varchar(30),
@.TIME datetime
set @.USER = (select suser_sname())
set @.TIME = (select getdate())
declare TableCursor cursor local static for
select COLUMN_NAME from information_schema.columns
where table_name = 'tbl_estimates' and column_name like '%ADJ%'
open TableCursor
fetch next from TableCursor into @.COLUMN
while @.@.fetch_status = 0
begin
set @.SQL1 = '
insert into tbl_audit (
a_table,
a_year,
a_version,
a_cost_centre,
a_account,
a_column,
a_old_value,
a_new_value,
a_date,
a_user )
select
''tbl_estimates'' as a_table,
a.est_year,
a.est_version,
a.est_cost_centre,
a.est_account,
'''+@.COLUMN+''' as est_column,
b.'+@.COLUMN+' as est_old_value,
a.'+@.COLUMN+' as est_new_value,
'''+cast(@.TIME as varchar)+''' as est_date,
'''+@.USER+''' as est_user
from inserted a
inner join tbl_estimates b on
a.est_year = b.est_year and
a.est_version = b.est_version and
a.est_cost_centre = b.est_cost_centre and
a.est_account = b.est_account
where
a.'+@.COLUMN+' != b.'+@.COLUMN
exec sp_executesql @.SQL1
fetch next from TableCursor into @.COLUMN
end
close TableCursor
deallocate TableCursor
I then tried to insert the data from inserted into a #temp table, but again
I think I would need to use exec sp_executesql to do this as surely the
#temp_table would have to be #temp_table+'@.USERNAME' otherwise would there
not be possibly duplicated data if other people are editing the table and
causing the trigger to fire at the same time....or maybe not?
Thanks for reading that! Can anyone offer any ideas as to how I might get
round this, or even a totally different approach if the one I've chosen is
just plain daft.
I thought I was being clever, but maybe thats where Im going wrong :)
Many thanks.
Steve'oNever put cursors in triggers. They just turn your set-based updates
into slow, inefficient and over-complex row-by-row operations.
Dynamic SQL is usually a bad idea too. The security implications of
dynamic code make it particularly unsuitable for audit processes. A
better method to keep this "generic" IMO is to generate static trigger
code automatically at design time using the information_schema.
Your trigger code can look something like the following, for example.
CREATE TRIGGER trg_foo_audit ON foo FOR INSERT, UPDATE, DELETE
AS
INSERT INTO audit_table (col1, col2, ...)
SELECT D.col1, D.col2, ...
FROM Inserted AS I
JOIN Deleted AS D
ON I.key_col = D.key_col
WHERE COALESCE(I.col1,'') <> COALESCE(D.col1,'')
AND COALESCE(I.col2,'') <> COALESCE(D.col2,'')
Hope this helps.
David Portas
SQL Server MVP
--|||Hi David, thanks for the reply!
With the dynamic sql I was just passing the column name and the username of
the person who update the data, all the variables are sql functions, how is
this bad security? Im not running the alter trigger statement each time,
sorry if I forgot to change that line, once I've written the trigger it
should stay static, with just the variables changing within the dynamic @.SQL
1
When you said:
>A
> better method to keep this "generic" IMO is to generate static trigger
> code automatically at design time using the information_schema.
Is that not what I had done? Using a curosr to loop through the
information.schema?
The slowness is an issue, it does make it much slower, as I've managed to
get a bit more working and can see its not good as it takes 1 second between
updates now.
From what your saying though, I have to write a long trigger per table, as
there are 20-40 columns which could be updated, so truck loads of OR..OR..OR
.
I was trying to keep a short single trigger which could quickly be re-used
if other tables need auditing.
Thanks again!
Steve.
"David Portas" wrote:

> Never put cursors in triggers. They just turn your set-based updates
> into slow, inefficient and over-complex row-by-row operations.
> Dynamic SQL is usually a bad idea too. The security implications of
> dynamic code make it particularly unsuitable for audit processes. A
> better method to keep this "generic" IMO is to generate static trigger
> code automatically at design time using the information_schema.
> Your trigger code can look something like the following, for example.
> CREATE TRIGGER trg_foo_audit ON foo FOR INSERT, UPDATE, DELETE
> AS
> INSERT INTO audit_table (col1, col2, ...)
> SELECT D.col1, D.col2, ...
> FROM Inserted AS I
> JOIN Deleted AS D
> ON I.key_col = D.key_col
> WHERE COALESCE(I.col1,'') <> COALESCE(D.col1,'')
> AND COALESCE(I.col2,'') <> COALESCE(D.col2,'')
> Hope this helps.
> --
> David Portas
> SQL Server MVP
> --
>|||> how is this bad security?
Putting dynamic SQL in a trigger means that every user who has to
update the data must be granted update permissions on the tables,
including the audit table. In other words you lose all the potential
benefits of securing your data through stored procedures and your audit
trail could be wide open to abuse. Whether that's a real issue may
depend on how your middle tier is implemented but if your data access
was suitably abstracted thorugh middle tier code (on a web server, say)
you probably wouldn't need a trigger anyway - you could just call an SP
to do the work. As you've used triggers I'm guessing you haven't
implemented a middle tier in such a way as to prevent users getting
direct access to tables. If I'm wrong then I'm not sure why you would
use a trigger to do this at all.
Read the following article for more information on the issues around
dynamic code:
http://www.sommarskog.se/dynamic_sql.html

> Is that not what I had done? Using a curosr to loop through the
> information.schema?
Yes, but I'm proposing that you don't do it in a trigger. Instead, do
it at *design time* in order to generate the (static) trigger code.
David Portas
SQL Server MVP
--|||I've been having problems replying all day, "MS is having problems with your
request".
Thanks David, for taking the time to explain what to most people is probably
obvious. I guess this is the problem with developing solutions with no
formal training, after a year the essential basics are missing and I've got
bad habbits, I shall read that link!
Could I then in theory use the after update trigger to fire a sproc which
does the updating of the tables, would this work? In that the user does not
have permission on the audit table, but the sproc is run by an account which
can only update the audit table and is NOT on the windows network (we use
windows authentication).
Or should I be reading more on the security chapters now too :) (I think I
know the answer to that one).
Currently there is no middle tier, just Access 2000 projects (.adp). Some
of our users are on dialup vpn connections, so server side work seemed to
make sense at the time.
"David Portas" wrote:

> Putting dynamic SQL in a trigger means that every user who has to
> update the data must be granted update permissions on the tables,
> including the audit table. In other words you lose all the potential
> benefits of securing your data through stored procedures and your audit
> trail could be wide open to abuse. Whether that's a real issue may
> depend on how your middle tier is implemented but if your data access
> was suitably abstracted thorugh middle tier code (on a web server, say)
> you probably wouldn't need a trigger anyway - you could just call an SP
> to do the work. As you've used triggers I'm guessing you haven't
> implemented a middle tier in such a way as to prevent users getting
> direct access to tables. If I'm wrong then I'm not sure why you would
> use a trigger to do this at all.
> Read the following article for more information on the issues around
> dynamic code:
> http://www.sommarskog.se/dynamic_sql.html
>
> Yes, but I'm proposing that you don't do it in a trigger. Instead, do
> it at *design time* in order to generate the (static) trigger code.
> --
> David Portas
> SQL Server MVP
> --
>|||Sorry, me again, having gone through your posts again Im as to what
your suggesting. ie
Automatically? I don't understand, design time is surely now, how would I
generate it automatically now and why?
Surely automatically implies at run-time, not design time?
Your example of :
INSERT INTO audit_table (col1, col2, ...)
SELECT D.col1, D.col2, ...
FROM Inserted AS I
JOIN Deleted AS D
ON I.key_col = D.key_col
WHERE COALESCE(I.col1,'') <> COALESCE(D.col1,'')
AND COALESCE(I.col2,'') <> COALESCE(D.col2,'')
How does this account for possibly more than 1 table with 20-40 columns
each? Surely this method means you have to specifically name ALL the column
s
which could be affected, and you have to have an audit table per source tabl
e
or you have a massive audit table which has most of its columns blank, as in
this example the columns need to match (insert into blah select blah).
The route I was looking at meant the only 1 audit table and only 1 trigger
no matter how many tables are to be audited (just change the source table
name and it will work).
My audit table only had one column for the column name, and the column name
was used as actual data rather than the crosstab look of boat loads of
columns to fit every circumstance.
Apologies, as Im sure I must have simply missunderstood, is there any chance
of a more detailed explanation of what "automatically" means and how your
example accounts for >1 table and loads of columns?
Thanks again.
Steve
"Steve'o" wrote:
> I've been having problems replying all day, "MS is having problems with yo
ur
> request".
> Thanks David, for taking the time to explain what to most people is probab
ly
> obvious. I guess this is the problem with developing solutions with no
> formal training, after a year the essential basics are missing and I've go
t
> bad habbits, I shall read that link!
> Could I then in theory use the after update trigger to fire a sproc which
> does the updating of the tables, would this work? In that the user does n
ot
> have permission on the audit table, but the sproc is run by an account whi
ch
> can only update the audit table and is NOT on the windows network (we use
> windows authentication).
> Or should I be reading more on the security chapters now too :) (I think
I
> know the answer to that one).
> Currently there is no middle tier, just Access 2000 projects (.adp). Some
> of our users are on dialup vpn connections, so server side work seemed to
> make sense at the time.
> "David Portas" wrote:
>|||Steve'o wrote:
> Sorry, me again, having gone through your posts again Im as to wh
at
> your suggesting. ie
>
>
> Automatically? I don't understand, design time is surely now, how would I
> generate it automatically now and why?
> Surely automatically implies at run-time, not design time?
>
What I imagine he's suggesting is that you move your automatic discovery
of table columns out of the trigger and into some code which writes a
script to create the triggers. Your triggers currently are operating
inefficiently because they are written to dynamic discover information
(the columns) at runtime which isn't dynamic at runtime. Every single
time the triggers fire, they suffer a penalty by having to rediscover
the same columns over and over again.
What's preferable is to write some small program or somewhat less small
SQL script which reads the information about your tables and their
columns from INFORMATION_SCHEMA views or other system info source and
then THAT would assemble and output a SQL script containing dynamically
generated CREATE TRIGGER instructions. The trigger code itself would
then be static and efficient because you've done the column discovery
externally.
For an example you can look at our OmniAudit program to create audit
triggers (hey, I did tell you how to do it yourself first). Just looking
at the triggers created by the trial version will give you some ideas
for your own trigger-generating process.
http://www.krell-software.com/omniaudit
Steve Troxell
http://www.krell-software.com

Audit Tables and triggers

Dear Group,

I would like to create an audit table that is created with a trigger that
reflects all the changes(insert, update and delete) that occur in table.

Say I have a table with

Subject_ID, visit_number, dob, weight, height, User_name, inputdate

The audit table would have .

Subject_ID, visit_number, dob, weight, height, User_name, inputdate,
edit_action, edit_reason.

Where the edit_action would be insert, update, delete; the edit_reason would
be the reason given for the edit.

Help with this would be great, since I am new to the world of triggers.

Thanks,

JeffJeff Magouirk (magouirkj@.njc.org) writes:
> I would like to create an audit table that is created with a trigger that
> reflects all the changes(insert, update and delete) that occur in table.
> Say I have a table with
> Subject_ID, visit_number, dob, weight, height, User_name,
> inputdate
> The audit table would have .
> Subject_ID, visit_number, dob, weight, height, User_name, inputdate,
> edit_action, edit_reason.
> Where the edit_action would be insert, update, delete; the edit_reason
> would be the reason given for the edit.
> Help with this would be great, since I am new to the world of triggers.

If you need to do to this on a broad scale, consider 3rd-party solutions.
Two that I usually recommend - although I've used none of them myself -
is SQLAudit from Red Matrix and Entegra from Lumigent. SQL Audit is
based on triggers, Entegra works from the transaction log.

But for a one-shot you could do:

CREATE TRIGGER tbl_audit_tri ON tbl FOR INSERT, UPDATE, DELETE

IF @.@.rowcount = 0
RETURN

IF EXISTS(SELECT * FROM inserted)
BEGIN
INSERT logtable (subject_id, ... edit_action)
SELECT subject_id, ...
CASE WHEN EXISTS (SELECT * FROM deleted)
THEN 'UPDATE'
ELSE 'INSERT'
FROM inserted
END
ELSE
BEGIN
INSERT logtable (subject_id, ... edit_action)
SELECT subject_id, ..., 'DELETE'
FROM delete
END

As you see I have left out edit_reason. This is because I don't know
what you mean with "edit_reason", and anyway it sounds like something
that can be quite difficult to get hold of from the trigger.

--
Erland Sommarskog, SQL Server MVP, esquel@.sommarskog.se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techin.../2000/books.asp

Wednesday, March 7, 2012

Audit one field in SQL Server 2005

Is it possible to use an update trigger to audit one field in a table? thanks
Hi Pete
An update trigger will fire no matter what columns are updated, but within
the trigger you can use a special construct IF UPDATE (column_name).
So you could check if one particular column was updated, and do what you
need to do, and otherwise, do nothing and return from the trigger.
HTH
Kalen Delaney, SQL Server MVP
www.InsideSQLServer.com
http://blog.kalendelaney.com
"pete" <pete@.discussions.microsoft.com> wrote in message
news:5F5E90A7-415F-491A-9A95-BC8E19CAD72C@.microsoft.com...
> Is it possible to use an update trigger to audit one field in a table?
> thanks

Audit one field in SQL Server 2005

Is it possible to use an update trigger to audit one field in a table? thanksHi Pete
An update trigger will fire no matter what columns are updated, but within
the trigger you can use a special construct IF UPDATE (column_name).
So you could check if one particular column was updated, and do what you
need to do, and otherwise, do nothing and return from the trigger.
--
HTH
Kalen Delaney, SQL Server MVP
www.InsideSQLServer.com
http://blog.kalendelaney.com
"pete" <pete@.discussions.microsoft.com> wrote in message
news:5F5E90A7-415F-491A-9A95-BC8E19CAD72C@.microsoft.com...
> Is it possible to use an update trigger to audit one field in a table?
> thanks

Audit one field in SQL Server 2005

Is it possible to use an update trigger to audit one field in a table? than
ksHi Pete
An update trigger will fire no matter what columns are updated, but within
the trigger you can use a special construct IF UPDATE (column_name).
So you could check if one particular column was updated, and do what you
need to do, and otherwise, do nothing and return from the trigger.
HTH
Kalen Delaney, SQL Server MVP
www.InsideSQLServer.com
http://blog.kalendelaney.com
"pete" <pete@.discussions.microsoft.com> wrote in message
news:5F5E90A7-415F-491A-9A95-BC8E19CAD72C@.microsoft.com...
> Is it possible to use an update trigger to audit one field in a table?
> thanks

Saturday, February 25, 2012

Audit

I want to register into a table each time a user creates, modifies or deletes any object in a database. It's not possible to add a trigger to the sysobjects table. What can I do?SQL 2005 will have that feature...the best I can tell you is to not allow them DDL Priviliges, and have them run all the DDL request through you...