<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Edwin M Sarmiento&gt;Change what? &#8211; Change Data Capture in SQL Server 2008 &#8211; Edwin M Sarmiento</title>
	<atom:link href="https://www.edwinmsarmiento.com/change-what-change-data-capture-in-sql-server-2008/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.edwinmsarmiento.com</link>
	<description>Intentional Excellence</description>
	<lastBuildDate>Mon, 13 Apr 2026 21:00:49 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
<site xmlns="com-wordpress:feed-additions:1">84283043</site>		<item>
		<title>&gt;Change what? &#8211; Change Data Capture in SQL Server 2008</title>
		<link>https://www.edwinmsarmiento.com/change-what-change-data-capture-in-sql-server-2008/</link>
		<comments>https://www.edwinmsarmiento.com/change-what-change-data-capture-in-sql-server-2008/#respond</comments>
		<pubDate>Fri, 12 Oct 2007 08:53:00 +0000</pubDate>
		<dc:creator>Edwin M Sarmiento</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://bassplayerdoc.wordpress.com/2007/10/12/change-what-change-data-capture-in-sql-server-2008</guid>

				<description><![CDATA[&#62;It must have been tough trying to capture INSERT, UPDATE and DELETE activities in a SQL Server database. Usually, developers may resort to creating DML triggers just to solve this problem in previous versions. The problem with this approach is that it introduces unnecessary overhead in the database engine. Another approach is to read the [&#8230;]]]></description>
					<content:encoded><![CDATA[<p>&gt;<span style="font-family:arial;">It must have been tough trying to capture <strong><span style="font-size:85%;">INSERT</span></strong>, <strong><span style="font-size:85%;">UPDATE</span></strong> and <strong><span style="font-size:85%;">DELETE</span></strong> activities in a SQL Server database. Usually, developers may resort to creating <strong><span style="font-size:85%;">DML</span></strong> triggers just to solve this problem in previous versions. The problem with this approach is that it introduces unnecessary overhead in the database engine. Another approach is to read the transaction log using either the <a href="http://bassplayerdoc.spaces.live.com/blog/cns!CED2A18FB2A30E11!235.entry">undocumented <strong><span style="font-size:85%;">DBCC LOG</span></strong> and <strong><span style="font-size:85%;">fn_dblog</span></strong></a> or using third-party tools like <a href="http://www.lumigent.com/">Lugiment Log Explorer</a>, <a href="http://www.apexsql.com/">ApexSQL Log</a>, or <a href="http://www.red-gate.com/">RedGate SQL Log Rescue</a>. In SQL Server 2005, the concept of <strong><span style="font-size:85%;">DDL</span></strong> triggers were introduced, thus making it easier to audit <strong><span style="font-size:85%;">DDL</span></strong> activities. This new feature of SQL Server 2008 called <strong><span style="font-size:85%;">Change Data Capture(CDC)</span></strong>, system stored procedures are used to mark which types of objects you want to audit, and the stored procedures take care of how the auditing occurs. How it works is that it captures <strong><span style="font-size:85%;">DML</span></strong> statements (this is quite interesting) asynchronously, reading the transaction logs (so much for third-party tools) and populates the <strong><span style="font-size:85%;">CDC</span></strong> table with the row&#8217;s data which change, and expose the changes through a relational interface which can be consumed easily. The downside of this is that the feature is only available on Enterprise and Developer Editions of SQL Server 2008. To use this feature, you have to enable it on the database level. Again, I&#8217;ll use the very familiar <strong><span style="font-size:85%;">Northwind</span></strong> database for this sample.</span><br /><span style="font-family:Arial;"></span><br /><span style="font-family:lucida grande;font-size:85%;"><strong><span style="color:#000099;">USE</span> Northwind</strong></span><br /><span style="font-family:lucida grande;font-size:85%;"><strong><span style="color:#000099;">EXEC</span> sys.sp_cdc_enable_db</strong></span></p>
<p><span style="font-family:arial;">Once <strong><span style="font-size:85%;">CDC</span> </strong>is enabled, it creates the corresponding objects are created: <strong><span style="font-size:85%;">cdc</span></strong> schema, <strong><span style="font-size:85%;">cdc</span></strong> user, metadata tables and other system objects. The thing about this is that you have to enable it on a per table basis (I don&#8217;t know why Microsoft chose to do it this way but if you decide to do this on all user-defined tables, you definitely need to write a script to accomplish this)</span><br /><span style="font-family:Arial;"></span><br /><span style="font-family:lucida grande;font-size:85%;"><strong><span style="color:#333399;">EXEC </span>sp_cdc_enable_table <span style="color:#990000;">&#8216;dbo&#8217;</span>, <span style="color:#990000;">&#8216;EmployeeTerritories&#8217;</span>, @role_name = <span style="color:#990000;">&#8216;cdc_role&#8217;</span>;</strong></span><br /><strong><span style="font-size:85%;"></span></strong><br /><span style="font-family:arial;">Just to explain the parameters passed to the stored procedure, the <strong><span style="font-size:85%;">dbo</span></strong> happens to be the schema in which the table belongs, <strong><span style="font-size:85%;">EmployeeTerritories</span></strong> is the name of the table which will be enabled for <strong><span style="font-size:85%;">CDC</span></strong> while the <strong><span style="font-size:85%;">@role_name</span></strong> parameter is the name of the database role used to have access to change data. If the role already exists, permissions are given to that role. If it doesn&#8217;t, it will be created with the specified name. Now, let&#8217;s simulate changes in the <strong><span style="font-size:85%;">dbo.EmployeeTerritories</span></strong> table (don&#8217;t worry about referential integrity as this has been taken cared of) </span><br /><span style="font-family:Arial;"><br /></span><span style="font-family:lucida grande;font-size:85%;"><strong><span style="color:#000099;">INSERT</span> dbo.EmployeeTerritories <span style="color:#000099;">VALUES</span> (4,98004), (4,98052);<br /><span style="color:#000099;">WAITFOR DELAY</span> <span style="color:#990000;">&#8217;00:00:05&#8242;</span>;<br /><span style="color:#666666;">UPDATE</span> dbo.EmployeeTerritories <span style="color:#000099;">SET</span> TerritoryID =80202<br />WHERE employeeid = 4 <span style="color:#666666;">AND</span> TerritoryID=98052;</strong></span><br /><span style="font-family:Arial;"></span><br /><span style="font-family:Arial;">These information is stored in a new table created named <strong><span style="font-size:85%;">schema_table_CT</span></strong> in the <strong><span style="font-size:85%;">cdc</span></strong> schema. In this case, it would be the <strong><span style="font-size:85%;">cdc.dbo_EmployeeTerritories_CT</span></strong> table. Querying this table is similar to executing the <strong><span style="font-size:85%;">DBCC LOG</span></strong> command in previous versions of SQL Server &#8211; it just doesn&#8217;t make sense. Good thing Microsoft came up with table-valued functions which makes querying this table a lot easier (but not straight-forward). One function which we can look at is the <strong><span style="font-size:85%;">cdc.fn_cdc_get_all_changes__</span></strong> function. This function returns one row for each change applied to the source table within the specified log sequence number (LSN) range. We don&#8217;t really care about LSN ranges but this is how SQL Server tracks all changes in the transaction log. This is also part of the information stored in our database backups. Since we have this data in our <strong><span style="font-size:85%;">cdc.dbo_EmployeeTerritories_CT</span></strong> table, we can use this data and pass it as a parameter in this function. Below is a sample script to use this function to query the <strong><span style="font-size:85%;">cdc.dbo_EmployeeTerritories_CT</span></strong> table but would return a more meaningful resultset</span></p>
<p><span style="color:#0000ff;"><br /><strong><span style="font-size:85%;">DECLARE</span></strong></span><strong><span style="font-size:85%;"> @begin_time <span style="color:#0000ff;">datetime</span><span style="color:#808080;">,</span> @end_time <span style="color:#0000ff;">datetime</span><span style="color:#808080;">,</span> @from_lsn <span style="color:#0000ff;">binary</span><span style="color:#808080;">(</span>10<span style="color:#808080;">),</span> @to_lsn <span style="color:#0000ff;">binary</span><span style="color:#808080;">(</span>10</span></strong><strong><span style="font-size:85%;color:#808080;">);<br /></span><span style="color:#008000;"></span></strong><br /></span><strong><span style="font-size:85%;"><span style="color:#008000;">&#8212; Obtain the beginning of the time interval.<br /></span><span style="color:#0000ff;">SET</span> @begin_time <span style="color:#808080;">=</span> <span style="color:#ff00ff;">GETDATE</span><span style="color:#808080;">()-</span>1</span></strong><span style="font-size:85%;color:#808080;"><strong>;<br /></strong></span><span style="color:#008000;"><br /><strong><span style="font-size:85%;">&#8212; Obtain the end of the time interval.<br /></span></strong></span><strong><span style="font-size:85%;"><span style="color:#0000ff;">SET</span> @end_time <span style="color:#808080;">=</span> <span style="color:#ff00ff;">GETDATE</span></span></strong><span style="font-size:85%;color:#808080;"><strong>();<br /></strong></span><span style="color:#008000;"><br /><strong><span style="font-size:85%;">&#8212; Map the time interval to a change data capture query range.<br /></span></strong></span><strong><span style="font-size:85%;"><span style="color:#0000ff;">SELECT</span> @from_lsn <span style="color:#808080;">=</span> sys.fn_cdc_map_time_to_lsn<span style="color:#808080;">(</span><span style="color:#ff0000;">&#8216;smallest greater than or equal&#8217;</span><span style="color:#808080;">,</span> @begin_time</span></strong><strong><span style="font-size:85%;"><span style="color:#808080;">);<br /></span><span style="color:#0000ff;">SELECT</span> @to_lsn <span style="color:#808080;">=</span> sys.fn_cdc_map_time_to_lsn<span style="color:#808080;">(</span><span style="color:#ff0000;">&#8216;largest less than or equal&#8217;</span><span style="color:#808080;">,</span> @end_time</span></strong><span style="font-size:85%;color:#808080;"><strong>);<br /></strong></span><span style="color:#008000;"><br /><strong><span style="font-size:85%;">&#8212; Return the changes occurring within the query window.<br /></span></strong></span><strong><span style="font-size:85%;"><span style="color:#0000ff;">SELECT</span> <span style="color:#808080;">*</span> <span style="color:#0000ff;">FROM</span> cdc<span style="color:#808080;">.</span>fn_cdc_get_all_changes_dbo_EmployeeTerritories<span style="color:#808080;">(</span>@from_lsn<span style="color:#808080;">,</span> @to_lsn<span style="color:#808080;">,</span> <span style="color:#ff0000;">&#8216;all&#8217;</span></span></strong><span style="font-size:85%;color:#808080;"><strong>);<br /></strong></span><strong><span style="font-size:85%;">GO<br /></span></strong><br /><span style="font-family:arial;">You might notice the new function introduced &#8211; <strong><span style="font-size:85%;">fn_cdc_map_time_to_lsn</span></strong>. This just returns the log sequence number (which we don&#8217;t really care about) corresponding to the specified time (which we are more familiar with). The resultset would be something we could understand. What we need to really look at is the <strong><span style="font-size:85%;">__$operation</span></strong> column which returns code values for the operations done for the specified table: 1 = delete, 2 = insert, 3 = update (before image), and 4 = update (after image). Imagine an <strong><span style="font-size:85%;">UPDATE</span></strong> statement to be like a <strong><span style="font-size:85%;">DELETE</span></strong> followed by an <span style="font-size:85%;"><strong>INSERT </strong></span><span style="font-size:100%;">that&#8217;s why you have a before and after images. Another way to translate the results of the <strong><span style="font-size:85%;">cdc.dbo_EmployeeTerritories_CT</span></strong> table is to use the query below</span></span><br /><span style="font-family:Arial;"></span><br /><strong><span style="font-size:85%;"><span style="color:#000099;">SELECT</span><br />operation = <span style="color:#000099;">CASE</span> __$operation<br /><span style="color:#000099;">WHEN</span> 1 <span style="color:#000099;">THEN</span> <span style="color:#990000;">&#8216;DELETE&#8217;<br /></span><span style="color:#000099;">WHEN</span> 2 <span style="color:#000099;">THEN</span> <span style="color:#990000;">&#8216;INSERT&#8217;</span><br /><span style="color:#000099;">WHEN</span> 3 <span style="color:#000099;">THEN</span> <span style="color:#993300;">&#8216;UPDATE(BEFORE)&#8217;</span><br /><span style="color:#000099;">WHEN</span> 4 <span style="color:#000099;">THEN</span> <span style="color:#993300;">&#8216;UPDATE(AFTER)&#8217;</span><br /><span style="color:#000099;">ELSE</span> <span style="color:#990000;">&#8216;UNDEFINED&#8217; </span><span style="color:#000099;">END</span>,<br />*<br /><span style="color:#000099;">FROM</span> cdc.dbo_EmployeeTerritories_CT</span></strong><br /><span style="font-family:Arial;"></span><br /><span style="font-family:arial;">Bear in mind though that the data in the <strong><span style="font-size:85%;">cdc</span></strong> tables are available within 3 days expressed in minutes (4320). You can clean this up when necessary using the <strong><span style="font-size:85%;">sp_cdc_cleanup_change_table</span></strong> stored procedure.</span><br /><span style="font-family:arial;"></span><br /><span style="font-family:arial;">This gives you an overview about change data capture and how you can use it in SQL Server 2008. Download the RC0 and start playing around with it. Check out my SQL Server 2008 videos at <a href="http://blogcastrepository.com/level5/sql2008/">BlogCastRepository.com</a></span></p>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/92377218009570869-8718548251825063073?l=bassplayerdoc.blogspot.com' alt='' /></div>
]]></content:encoded>
			

		<wfw:commentRss>https://www.edwinmsarmiento.com/change-what-change-data-capture-in-sql-server-2008/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
				<post-id xmlns="com-wordpress:feed-additions:1">33</post-id>	</item>
	</channel>
</rss>