<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>Question Re: Activity Log Design in Technology Q&amp;A</title>
    <link>https://community.sap.com/t5/technology-q-a/activity-log-design/qaa-p/13841026#M4871869</link>
    <description>&lt;P&gt;See: &lt;A href="http://sqlanywhere.blogspot.ca/2008/02/tip-triggering-audit-trail.html"&gt;Tip: Triggering an Audit Trai&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Also: &lt;A href="http://sqlanywhere.blogspot.ca/2009/02/revisited-triggering-audit-trail.html"&gt;Revisited: Triggering an Audit Trail&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Plus: &lt;A href="http://sqlanywhere.blogspot.ca/2009/03/alter-table-and-audit-trail.html"&gt;ALTER TABLE and the Audit Trail&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;The code described has been in production in one application for several years, and the resulting data has been invaluable when tracking down the cause of various problems.&lt;/P&gt;</description>
    <pubDate>Wed, 14 Nov 2012 08:46:30 GMT</pubDate>
    <dc:creator>Breck_Carter</dc:creator>
    <dc:date>2012-11-14T08:46:30Z</dc:date>
    <item>
      <title>Activity Log Design</title>
      <link>https://community.sap.com/t5/technology-q-a/activity-log-design/qaq-p/13841023</link>
      <description>&lt;P&gt;How would you design an activity log for a table MyTable in SQL Anywhere?&lt;BR /&gt;
&lt;/P&gt;
&lt;P&gt;For simplicity assume that only one table's activity needs to be logged.&lt;BR /&gt;
&lt;/P&gt;
&lt;P&gt;I'm thinking there would be Insert, Delete, and Update triggers on MyTable to insert into the ActivityLog table something like:&lt;/P&gt;
&lt;DIV class="codehilite"&gt;&lt;PRE&gt;&lt;SPAN class="n"&gt;ActivityID&lt;/SPAN&gt; &lt;SPAN class="n"&gt;integer&lt;/SPAN&gt; &lt;SPAN class="n"&gt;default&lt;/SPAN&gt; &lt;SPAN class="n"&gt;autoincrement&lt;/SPAN&gt;&lt;SPAN class="p"&gt;,&lt;/SPAN&gt;
&lt;SPAN class="n"&gt;UserID&lt;/SPAN&gt; &lt;SPAN class="n"&gt;integer&lt;/SPAN&gt;&lt;SPAN class="p"&gt;,&lt;/SPAN&gt;
&lt;SPAN class="n"&gt;OnDate&lt;/SPAN&gt; &lt;SPAN class="n"&gt;timestamp&lt;/SPAN&gt; &lt;SPAN class="p"&gt;,&lt;/SPAN&gt;
&lt;SPAN class="n"&gt;Type&lt;/SPAN&gt; &lt;SPAN class="n"&gt;char&lt;/SPAN&gt;&lt;SPAN class="p"&gt;(&lt;/SPAN&gt;&lt;SPAN class="mi"&gt;1&lt;/SPAN&gt;&lt;SPAN class="p"&gt;),&lt;/SPAN&gt; &lt;SPAN class="sr"&gt;//&lt;/SPAN&gt; &lt;SPAN class="p"&gt;(&lt;/SPAN&gt;&lt;SPAN class="n"&gt;insert&lt;/SPAN&gt;&lt;SPAN class="p"&gt;,&lt;/SPAN&gt; &lt;SPAN class="nb"&gt;delete&lt;/SPAN&gt;&lt;SPAN class="p"&gt;,&lt;/SPAN&gt; &lt;SPAN class="n"&gt;update&lt;/SPAN&gt;&lt;SPAN class="p"&gt;)&lt;/SPAN&gt;
&lt;SPAN class="n"&gt;KeyID&lt;/SPAN&gt; &lt;SPAN class="n"&gt;integer&lt;/SPAN&gt;&lt;SPAN class="p"&gt;,&lt;/SPAN&gt; &lt;SPAN class="sr"&gt;//&lt;/SPAN&gt; &lt;SPAN class="n"&gt;of&lt;/SPAN&gt; &lt;SPAN class="n"&gt;affected&lt;/SPAN&gt; &lt;SPAN class="n"&gt;row&lt;/SPAN&gt;
&lt;SPAN class="n"&gt;FieldUpdated&lt;/SPAN&gt; &lt;SPAN class="n"&gt;varchar&lt;/SPAN&gt;&lt;SPAN class="p"&gt;(&lt;/SPAN&gt;&lt;SPAN class="mi"&gt;50&lt;/SPAN&gt;&lt;SPAN class="p"&gt;),&lt;/SPAN&gt; &lt;SPAN class="sr"&gt;//&lt;/SPAN&gt;&lt;SPAN class="p"&gt;(&lt;/SPAN&gt;&lt;SPAN class="n"&gt;null&lt;/SPAN&gt; &lt;SPAN class="k"&gt;for&lt;/SPAN&gt; &lt;SPAN class="n"&gt;insert&lt;/SPAN&gt;&lt;SPAN class="o"&gt;/&lt;/SPAN&gt;&lt;SPAN class="nb"&gt;delete&lt;/SPAN&gt;&lt;SPAN class="p"&gt;)&lt;/SPAN&gt;
&lt;SPAN class="n"&gt;FieldType&lt;/SPAN&gt; &lt;SPAN class="sr"&gt;//&lt;/SPAN&gt; &lt;SPAN class="p"&gt;?&lt;/SPAN&gt;
&lt;SPAN class="n"&gt;OldValue&lt;/SPAN&gt;  &lt;SPAN class="sr"&gt;//&lt;/SPAN&gt; &lt;SPAN class="p"&gt;?&lt;/SPAN&gt;
&lt;SPAN class="n"&gt;NewValue&lt;/SPAN&gt;  &lt;SPAN class="sr"&gt;//&lt;/SPAN&gt; &lt;SPAN class="p"&gt;?&lt;/SPAN&gt;
&lt;/PRE&gt;&lt;/DIV&gt;


&lt;P&gt;Based on that structure (which may not be the best solution), Inserts and Deletes are fairly easy. However, for an Update the trigger would have to compare every field's new value against its old value to determine the inserts to make, and you would need to remember to adjust the trigger if the table structure changed.&lt;BR /&gt;
&lt;/P&gt;
&lt;P&gt;Is there some system function or other way to specifically identify only the fields updated that caused the trigger to fire to avoid defining each column individually in a comparison?&lt;/P&gt;
&lt;P&gt;Any thoughts, hints, or general directions are appreciated. &lt;/P&gt;</description>
      <pubDate>Tue, 13 Nov 2012 17:42:30 GMT</pubDate>
      <guid>https://community.sap.com/t5/technology-q-a/activity-log-design/qaq-p/13841023</guid>
      <dc:creator>former_SQLA_member1694868</dc:creator>
      <dc:date>2012-11-13T17:42:30Z</dc:date>
    </item>
    <item>
      <title>Re: Activity Log Design</title>
      <link>https://community.sap.com/t5/technology-q-a/activity-log-design/qaa-p/13841024#M4871867</link>
      <description>&lt;P&gt;Just a few thoughts:&lt;/P&gt;
&lt;P&gt;I guess you will use AFTER ... FOR EACH ROW triggers to log the contents. For UPDATE, they have the advantage to be fired only when the columns's values are really changed, i.e. the following won't trigger the trigger:&lt;/P&gt;
&lt;DIV class="codehilite"&gt;&lt;PRE&gt;&lt;SPAN class="n"&gt;UPDATE&lt;/SPAN&gt; &lt;SPAN class="n"&gt;myTable&lt;/SPAN&gt; &lt;SPAN class="n"&gt;set&lt;/SPAN&gt; &lt;SPAN class="n"&gt;myCol&lt;/SPAN&gt; &lt;SPAN class="o"&gt;=&lt;/SPAN&gt; &lt;SPAN class="n"&gt;myCol&lt;/SPAN&gt;&lt;SPAN class="p"&gt;;&lt;/SPAN&gt;
&lt;/PRE&gt;&lt;/DIV&gt;


&lt;P&gt;(CAVEAT: Note that in a case-independent database, a change of col1 from 'a' to 'A' is considered a change (and the trigger is fired) even if both values are the same when compared.)&lt;/P&gt;
&lt;P&gt;We do use a similar method to record a "history" of several tables but do only monitor a list of "relevant columns". For these, we use "AFTER UPDATE OF &amp;lt;column list=""&amp;gt;" triggers to log if any of these columns has been modified. However, we do log the row contents of all columns before and after, so we do not log only the modified columns.&lt;/P&gt;
&lt;HR /&gt;
&lt;P&gt;If you really want to log only modified columns, and want to have exactly one log entry for each modified column, a straightforward (but possibly non-performant) method would be to &lt;STRONG&gt;define an AFTER UPDATE OF &amp;lt;mycolumn&amp;gt; trigger for each of these columns&lt;/STRONG&gt;. The "comparison logic" (i.e. whether the column has been changed) would then be coded in the trigger's definition itself and not in its body. These triggers will obviously be very easy to code.&lt;/P&gt;
&lt;P&gt;The obvious drawback (besides a possible inefficiency) would be that you will need to add an AFTER UPDATE OF trigger for each new column that should be monitored. On the other hand, adding a new trigger might be easier/less error-prone than modifying one "big" trigger.&lt;/P&gt;
&lt;HR /&gt;
&lt;P&gt;Another soulution would be to use &lt;STRONG&gt;only one AFTER UPDATE OF &amp;lt;list of all relevant columns&amp;gt; trigger&lt;/STRONG&gt; and then to use &lt;STRONG&gt;one IF UPDATE(myColumn) test for each relevant column&lt;/STRONG&gt; to distinguish between the several columns, something like&lt;/P&gt;
&lt;DIV class="codehilite"&gt;&lt;PRE&gt;&lt;SPAN class="k"&gt;CREATE&lt;/SPAN&gt; &lt;SPAN class="k"&gt;TRIGGER&lt;/SPAN&gt; &lt;SPAN class="n"&gt;TRU_MyTable&lt;/SPAN&gt; &lt;SPAN class="k"&gt;AFTER&lt;/SPAN&gt; &lt;SPAN class="k"&gt;UPDATE&lt;/SPAN&gt; &lt;SPAN class="k"&gt;OF&lt;/SPAN&gt; &lt;SPAN class="n"&gt;column2&lt;/SPAN&gt;&lt;SPAN class="p"&gt;,&lt;/SPAN&gt; &lt;SPAN class="n"&gt;column3&lt;/SPAN&gt;&lt;SPAN class="p"&gt;,&lt;/SPAN&gt; &lt;SPAN class="p"&gt;...&lt;/SPAN&gt;
&lt;SPAN class="k"&gt;ON&lt;/SPAN&gt; &lt;SPAN class="n"&gt;MyTable&lt;/SPAN&gt;
&lt;SPAN class="k"&gt;REFERENCING&lt;/SPAN&gt; &lt;SPAN class="k"&gt;OLD&lt;/SPAN&gt; &lt;SPAN class="k"&gt;AS&lt;/SPAN&gt; &lt;SPAN class="n"&gt;O&lt;/SPAN&gt;
&lt;SPAN class="k"&gt;REFERENCING&lt;/SPAN&gt; &lt;SPAN class="k"&gt;NEW&lt;/SPAN&gt; &lt;SPAN class="k"&gt;AS&lt;/SPAN&gt; &lt;SPAN class="n"&gt;N&lt;/SPAN&gt;
&lt;SPAN class="k"&gt;FOR&lt;/SPAN&gt; &lt;SPAN class="k"&gt;EACH&lt;/SPAN&gt; &lt;SPAN class="k"&gt;ROW&lt;/SPAN&gt;
&lt;SPAN class="k"&gt;BEGIN&lt;/SPAN&gt;
   &lt;SPAN class="p"&gt;...&lt;/SPAN&gt;
   &lt;SPAN class="n"&gt;IF&lt;/SPAN&gt; &lt;SPAN class="k"&gt;UPDATE&lt;/SPAN&gt;&lt;SPAN class="p"&gt;(&lt;/SPAN&gt;&lt;SPAN class="n"&gt;column2&lt;/SPAN&gt;&lt;SPAN class="p"&gt;)&lt;/SPAN&gt; &lt;SPAN class="k"&gt;THEN&lt;/SPAN&gt;
      &lt;SPAN class="c1"&gt;-- log column2 modification&lt;/SPAN&gt;
   &lt;SPAN class="k"&gt;END&lt;/SPAN&gt; &lt;SPAN class="n"&gt;IF&lt;/SPAN&gt;&lt;SPAN class="p"&gt;;&lt;/SPAN&gt;
   &lt;SPAN class="n"&gt;IF&lt;/SPAN&gt; &lt;SPAN class="k"&gt;UPDATE&lt;/SPAN&gt;&lt;SPAN class="p"&gt;(&lt;/SPAN&gt;&lt;SPAN class="n"&gt;column3&lt;/SPAN&gt;&lt;SPAN class="p"&gt;)&lt;/SPAN&gt; &lt;SPAN class="k"&gt;THEN&lt;/SPAN&gt;
      &lt;SPAN class="c1"&gt;-- log column3 modification&lt;/SPAN&gt;
   &lt;SPAN class="k"&gt;END&lt;/SPAN&gt; &lt;SPAN class="n"&gt;IF&lt;/SPAN&gt;&lt;SPAN class="p"&gt;;&lt;/SPAN&gt;
   &lt;SPAN class="p"&gt;...&lt;/SPAN&gt;
&lt;SPAN class="k"&gt;END&lt;/SPAN&gt;&lt;SPAN class="p"&gt;;&lt;/SPAN&gt;
&lt;/PRE&gt;&lt;/DIV&gt;


&lt;P&gt;Note: I have not tested whether the test for UDATE(column) is only true when its value has been changed - or is true when it has been used in the UPDATE's SET clause.&lt;/P&gt;</description>
      <pubDate>Wed, 14 Nov 2012 03:57:48 GMT</pubDate>
      <guid>https://community.sap.com/t5/technology-q-a/activity-log-design/qaa-p/13841024#M4871867</guid>
      <dc:creator>VolkerBarth</dc:creator>
      <dc:date>2012-11-14T03:57:48Z</dc:date>
    </item>
    <item>
      <title>Re: Activity Log Design</title>
      <link>https://community.sap.com/t5/technology-q-a/activity-log-design/qaa-p/13841025#M4871868</link>
      <description>&lt;P&gt;I thought it would be a good idea to use &lt;EM&gt;Trigger operation conditions&lt;/EM&gt;.&lt;/P&gt;
&lt;DIV class="codehilite"&gt;&lt;PRE&gt;&lt;SPAN class="n"&gt;if&lt;/SPAN&gt; &lt;SPAN class="n"&gt;UPDATING&lt;/SPAN&gt;&lt;SPAN class="p"&gt;(&lt;/SPAN&gt; &lt;SPAN class="s1"&gt;'Column Name'&lt;/SPAN&gt; &lt;SPAN class="p"&gt;)&lt;/SPAN&gt; &lt;SPAN class="k"&gt;then&lt;/SPAN&gt; 
    &lt;SPAN class="p"&gt;...&lt;/SPAN&gt;
&lt;SPAN class="k"&gt;end&lt;/SPAN&gt; &lt;SPAN class="n"&gt;if&lt;/SPAN&gt;&lt;SPAN class="p"&gt;;&lt;/SPAN&gt;
&lt;SPAN class="n"&gt;if&lt;/SPAN&gt; &lt;SPAN class="n"&gt;UPDATING&lt;/SPAN&gt;&lt;SPAN class="p"&gt;(&lt;/SPAN&gt; &lt;SPAN class="o"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN class="k"&gt;Variable&lt;/SPAN&gt;&lt;SPAN class="o"&gt;&amp;gt;&lt;/SPAN&gt; &lt;SPAN class="p"&gt;)&lt;/SPAN&gt; &lt;SPAN class="k"&gt;then&lt;/SPAN&gt; 
    &lt;SPAN class="p"&gt;...&lt;/SPAN&gt;
&lt;SPAN class="k"&gt;end&lt;/SPAN&gt; &lt;SPAN class="n"&gt;if&lt;/SPAN&gt;&lt;SPAN class="p"&gt;;&lt;/SPAN&gt;
&lt;/PRE&gt;&lt;/DIV&gt;


&lt;P&gt;But it is not possible to use a variable instead of a hard coded character string. &lt;/P&gt;
&lt;P&gt;We use PowerDesigner to manage our DB Schema. We have enhanced it so that it will generate all needed triggers based on the data model. &lt;/P&gt;</description>
      <pubDate>Wed, 14 Nov 2012 06:27:53 GMT</pubDate>
      <guid>https://community.sap.com/t5/technology-q-a/activity-log-design/qaa-p/13841025#M4871868</guid>
      <dc:creator>thomas_duemesnil</dc:creator>
      <dc:date>2012-11-14T06:27:53Z</dc:date>
    </item>
    <item>
      <title>Re: Activity Log Design</title>
      <link>https://community.sap.com/t5/technology-q-a/activity-log-design/qaa-p/13841026#M4871869</link>
      <description>&lt;P&gt;See: &lt;A href="http://sqlanywhere.blogspot.ca/2008/02/tip-triggering-audit-trail.html"&gt;Tip: Triggering an Audit Trai&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Also: &lt;A href="http://sqlanywhere.blogspot.ca/2009/02/revisited-triggering-audit-trail.html"&gt;Revisited: Triggering an Audit Trail&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Plus: &lt;A href="http://sqlanywhere.blogspot.ca/2009/03/alter-table-and-audit-trail.html"&gt;ALTER TABLE and the Audit Trail&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;The code described has been in production in one application for several years, and the resulting data has been invaluable when tracking down the cause of various problems.&lt;/P&gt;</description>
      <pubDate>Wed, 14 Nov 2012 08:46:30 GMT</pubDate>
      <guid>https://community.sap.com/t5/technology-q-a/activity-log-design/qaa-p/13841026#M4871869</guid>
      <dc:creator>Breck_Carter</dc:creator>
      <dc:date>2012-11-14T08:46:30Z</dc:date>
    </item>
  </channel>
</rss>

