<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title type="html">Steve Kass</title><subtitle type="html">SQL MVP since 2002
Professor of Mathematics and Computer Science at Drew University</subtitle><id>http://sqlblog.com/blogs/steve_kass/atom.aspx</id><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/steve_kass/default.aspx" /><link rel="self" type="application/atom+xml" href="http://sqlblog.com/blogs/steve_kass/atom.aspx" /><generator uri="http://communityserver.org" version="2.1.61129.1">Community Server</generator><updated>2009-04-29T01:57:00Z</updated><entry><title>How to convert Books Online ms-help: links to MSDN Library http: links [bookmarklet included]</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/steve_kass/archive/2009/08/05/how-to-convert-books-online-ms-help-links-to-msdn-library-http-links-bookmarklet-included.aspx" /><id>http://sqlblog.com/blogs/steve_kass/archive/2009/08/05/how-to-convert-books-online-ms-help-links-to-msdn-library-http-links-bookmarklet-included.aspx</id><published>2009-08-05T03:11:00Z</published><updated>2009-08-05T03:11:00Z</updated><content type="html">As you know, Books Online is available in two convenient locations. It's online as part of the MSDN Library, and it's offline as a Document Explorer help collection. Topics are accessible by URIs in each, but the URIs don't match. For example: Books Online Topic: CREATE STATISTICS (Transact-SQL) Document Explorer URI: ms-help://MS.SQLCC.v10/MS.SQLSVR.v10.en/s10de_6tsql/html/b23e2f6b-076c-4e6d-9281-764bdb616ad2.htm MSDN Library URI: http://msdn.microsoft.com/en-us/library/ms188038.aspx A while ago,...(&lt;a href="http://sqlblog.com/blogs/steve_kass/archive/2009/08/05/how-to-convert-books-online-ms-help-links-to-msdn-library-http-links-bookmarklet-included.aspx"&gt;read more&lt;/a&gt;)&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=15783" width="1" height="1"&gt;</content><author><name>skass</name><uri>http://sqlblog.com/members/skass.aspx</uri></author><category term="Books Online" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/Books+Online/default.aspx" /><category term="MSDN" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/MSDN/default.aspx" /><category term="bookmarklet" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/bookmarklet/default.aspx" /><category term="URL translation" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/URL+translation/default.aspx" /></entry><entry><title>DELETE FROM Where?</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/steve_kass/archive/2009/04/30/delete-from-where.aspx" /><id>http://sqlblog.com/blogs/steve_kass/archive/2009/04/30/delete-from-where.aspx</id><published>2009-04-30T21:48:00Z</published><updated>2009-04-30T21:48:00Z</updated><content type="html">&lt;P&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;For years, SQL Server has supported a (second) FROM clause in UPDATE and DELETE statements. Its behavior isn't always deterministic, a fact Microsoft points out in the documentation. &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;Today, someone was surprised by&amp;nbsp;the basic semantics of DELETE .. FROM.&amp;nbsp;This probably happens a lot, but fortunately today's surprisee&amp;nbsp;posted &lt;A title="Connect item #436328" href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=436328"&gt;this Connect item&lt;/A&gt; because the following&amp;nbsp;statement didn't do what the documentation seemed to say it would:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;&lt;FONT color=#0000ff&gt;
&lt;P&gt;DELETE&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;FROM&lt;/FONT&gt; t2&lt;BR&gt;&lt;FONT color=#0000ff&gt;FROM&lt;/FONT&gt; t1 &lt;FONT color=#0000ff&gt;AS&lt;/FONT&gt; t2&lt;/P&gt;
&lt;P&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;Quick now, what table does this truncate?&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;You're in good company if you said t2, which is the wrong answer. &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;The statement truncates t1, however, not t2. In fact, this &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;DELETE statement contains no reference to the table t2, assuming there even is one. Here, t2 is only an alias, and the statement is semantically identical to&lt;BR&gt;&lt;BR&gt;&lt;FONT color=#0000ff&gt;DELETE&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;FROM&lt;/FONT&gt; ThisIsAnAliasNotATable&lt;BR&gt;&lt;FONT color=#0000ff&gt;FROM&lt;/FONT&gt; t1 &lt;FONT color=#0000ff&gt;AS&lt;/FONT&gt; ThisIsAnAliasNotATable&lt;/P&gt;
&lt;P&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;When there are two FROM clauses in a DELETE statement, the first FROM clause is interpreted in the context of the table source defined by the second one, which is analogous to how SELECT works. The following query selects rows from t1, not t2, and that's no surprise:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;&lt;FONT color=#0000ff&gt;
&lt;P&gt;SELECT&lt;/FONT&gt; t2&lt;FONT color=#808080&gt;.&lt;/FONT&gt;a&lt;BR&gt;&lt;FONT color=#0000ff&gt;FROM&lt;/FONT&gt; t1 &lt;FONT color=#0000ff&gt;AS&lt;/FONT&gt; t2&lt;/P&gt;
&lt;P&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;If you think about it, you should&amp;nbsp;agree that different behavior for DELETE would be very bad. If SQL Server produced what Vitaliy expected, someone could create tables with names used somewhere as aliases, and cause UPDATE and DELETE statements to stop updating the tables they were supposed to update. &lt;/SPAN&gt;&lt;/SPAN&gt;What makes the DELETE behavior more confusing than the SELECT behavior is the fact that in the case of DELETE, the keyword FROM can be used twice. It you write DELETE .. FROM statements with two FROMs,&amp;nbsp;remember that the bottom FROM clause is the "outer" one in the sense of scope. It should be considered first, as is clearer in this DELETE statement, which is equivalent to the one that suprised Vitaliy:&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;&lt;FONT color=#0000ff&gt;
&lt;P&gt;WITH&lt;/FONT&gt; t2 &lt;FONT color=#0000ff&gt;AS &lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;BR&gt;&amp;nbsp; &lt;/FONT&gt;&lt;FONT color=#0000ff&gt;SELECT&lt;/FONT&gt;&amp;nbsp;* &lt;FONT color=#0000ff&gt;FROM&lt;/FONT&gt; t1&lt;BR&gt;&lt;FONT color=#808080&gt;)&lt;BR&gt;&amp;nbsp; &lt;/FONT&gt;&lt;FONT color=#0000ff&gt;DELETE&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;FROM&lt;/FONT&gt; t2&lt;/P&gt;
&lt;P&gt;For the record, this CTE-based DELETE is just as non-standard as the DELETE .. FROM, but it's less confusing. If you can't easily (or effeciently) avoid the use of DELETE .. FROM, consider rewriting DELETE .. FROM as a CTE to reduce the chance of confusion.&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;&lt;SPAN style="TEXT-ALIGN:left;FONT-FAMILY:Verdana;FONT-SIZE:11px;" class=Apple-style-span&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=13678" width="1" height="1"&gt;</content><author><name>skass</name><uri>http://sqlblog.com/members/skass.aspx</uri></author><category term="T-SQL language extensions" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/T-SQL+language+extensions/default.aspx" /><category term="Connect" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/Connect/default.aspx" /><category term="T-SQL" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/T-SQL/default.aspx" /><category term="DELETE" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/DELETE/default.aspx" /><category term="nonstandard" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/nonstandard/default.aspx" /></entry><entry><title>It's 2008, and @@ROWCOUNT ain't what it used to be. Don't use it in triggers.</title><link rel="alternate" type="text/html" href="http://sqlblog.com/blogs/steve_kass/archive/2009/04/29/It_2700_s-2008-and-rowcount-ain_2700_t-what-it-used-to-be.-Don_2700_t-use-it-in-triggers_2100_.aspx" /><id>http://sqlblog.com/blogs/steve_kass/archive/2009/04/29/It_2700_s-2008-and-rowcount-ain_2700_t-what-it-used-to-be.-Don_2700_t-use-it-in-triggers_2100_.aspx</id><published>2009-04-29T04:57:00Z</published><updated>2009-04-29T04:57:00Z</updated><content type="html">&lt;SPAN style="WIDOWS:2;TEXT-TRANSFORM:none;TEXT-INDENT:0px;BORDER-COLLAPSE:separate;FONT:16px 'Times New Roman';WHITE-SPACE:normal;ORPHANS:2;LETTER-SPACING:normal;WORD-SPACING:0px;-webkit-text-size-adjust:auto;-webkit-border-horizontal-spacing:0px;-webkit-border-vertical-spacing:0px;-webkit-text-decorations-in-effect:none;-webkit-text-stroke-width:0px;" class=Apple-style-span&gt;
&lt;DIV style="PADDING-BOTTOM:8px;PADDING-LEFT:8px;PADDING-RIGHT:8px;FONT-FAMILY:Arial, Helvetica, sans-serif;FONT-SIZE:10pt;PADDING-TOP:8px;"&gt;
&lt;P&gt;During SQL Server 2008 beta testing, Aaron Bertrand &lt;A title="Connect Item 298395" href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=298395"&gt;noted&lt;/A&gt; that the value of @@rowcount inside a trigger could be unexpected, if the triggering statement was MERGE.&lt;/P&gt;
&lt;P&gt;The consequences of this can be pretty bad, but fortunately there's a simple workaround. You need to do something if anyone might invoke MERGE against tables with triggers that contain @@rowcount checks &lt;/P&gt;
&lt;P&gt;A MERGE statement can cause as many as three triggers to fire. Within each of them, the value of @@rowcount is the number of rows affected by the entire MERGE statement, i.e. the total number rows inserted, updated, &lt;I&gt;or&lt;/I&gt; deleted by the various merge clauses.&lt;/P&gt;
&lt;P&gt;Books Online mentions this in the article on MERGE: &lt;I&gt;When used after MERGE, @@ROWCOUNT (Transact-SQL) returns the total number of rows inserted, updated, and deleted to the client.&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;Elsewhere, however, Books Online continues to give old advice that as of 2008 is not good advice. For example, in the article Multirow considerations for DML triggers, Books Online says, &lt;I&gt;For example, the&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;CODE&gt;@@ROWCOUNT&lt;/CODE&gt;&lt;SPAN class=Apple-converted-space&gt;&amp;nbsp;&lt;/SPAN&gt;function can be used in the logic of the trigger to distinguish between a single and a multirow insert.&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;Not so, I'm afraid. The value of @@rowcount in an INSERT trigger, say, will always be at least equal to the number of rows inserted, but it can be greater. For example, a MERGE statement could have an INSERT action that doesn't occur, but an UPDATE one that updates 3 rows. The INSERT trigger will be called, because the MERGE statement's INSERT section "inserted zero rows."&lt;/P&gt;
&lt;P&gt;Here's an example from AdventureWorks2008 to show what can go wrong.&lt;/P&gt;
&lt;P&gt;I've added a GrandTotal table containing one row and column. GrandTotal.gt is supposed to keep track of the grand total of all purchase SubTotals.&lt;/P&gt;
&lt;P&gt;This code creates the table and gives it a value that's initially correct for the data in AdventureWorks2008:&lt;/P&gt;&lt;FONT color=#0000ff&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;USE&lt;/FONT&gt; AdventureWorks2008&lt;FONT color=#808080&gt;;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;GO&lt;BR&gt;&amp;nbsp; CREATE&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;TABLE&lt;/FONT&gt; GrandTotal&lt;FONT color=#808080&gt;(&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp; gt &lt;FONT color=#0000ff&gt;DECIMAL&lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;/FONT&gt;18&lt;FONT color=#808080&gt;,&lt;/FONT&gt;2&lt;FONT color=#808080&gt;)&lt;BR&gt;);&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;INSERT&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;INTO&lt;/FONT&gt; GrandTotal;&lt;BR&gt;&lt;FONT color=#0000ff&gt;SELECT&lt;/FONT&gt; &lt;FONT color=#ff00ff&gt;sum&lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;/FONT&gt;SubTotal&lt;FONT color=#808080&gt;);&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;FROM&lt;/FONT&gt; Purchasing&lt;FONT color=#808080&gt;.&lt;/FONT&gt;PurchaseOrderHeader&lt;FONT color=#808080&gt;;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;GO&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;&lt;FONT color=#000000&gt;This code creates a trigger to update the grand total whenever new line items are inserted into the table:&lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;CREATE&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;TRIGGER&lt;/FONT&gt; NewPODetail3&lt;BR&gt;&lt;FONT color=#0000ff&gt;ON&lt;/FONT&gt; Purchasing&lt;FONT color=#808080&gt;.&lt;/FONT&gt;PurchaseOrderDetail&lt;BR&gt;&lt;FONT color=#0000ff&gt;FOR&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;INSERT&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;AS&lt;BR&gt;IF&lt;/FONT&gt; &lt;FONT color=#ff00ff&gt;@@ROWCOUNT&lt;/FONT&gt; &lt;FONT color=#808080&gt;&amp;gt;&lt;/FONT&gt; 0&lt;BR&gt;&lt;FONT color=#0000ff&gt;UPDATE&lt;/FONT&gt; GrandTotal &lt;FONT color=#0000ff&gt;SET&lt;BR&gt;&lt;/FONT&gt;gt &lt;FONT color=#808080&gt;+=&lt;/FONT&gt;&lt;FONT color=#0000ff&gt; &lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;SELECT&lt;/FONT&gt; &lt;FONT color=#ff00ff&gt;SUM&lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;/FONT&gt;LineTotal&lt;FONT color=#808080&gt;) &lt;/FONT&gt;&lt;FONT color=#0000ff&gt;FROM&lt;/FONT&gt; inserted);&lt;BR&gt;&lt;FONT color=#0000ff&gt;GO&lt;/FONT&gt;&lt;/P&gt;&lt;FONT color=#0000ff&gt;&lt;/FONT&gt;
&lt;DIV&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;FONT color=#000000&gt;And this MERGE statement (enclosed in a rolled-back transaction here so that no data in the database is modified by this test script) has the unintended result of updating the grand total from $63,791,994.84 to NULL. &lt;/FONT&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;begin&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;tran&lt;BR&gt;select&lt;/FONT&gt; &lt;FONT color=#808080&gt;*&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;From&lt;/FONT&gt; GrandTotal&lt;FONT color=#808080&gt;;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;merge&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;into&lt;/FONT&gt; Purchasing&lt;FONT color=#808080&gt;.&lt;/FONT&gt;PurchaseOrderDetail &lt;FONT color=#0000ff&gt;as&lt;/FONT&gt; P&lt;BR&gt;&lt;FONT color=#0000ff&gt;using &lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;&amp;nbsp; select&lt;/FONT&gt; 2&lt;FONT color=#808080&gt;,&lt;/FONT&gt;&lt;FONT color=#ff0000&gt;'20010715'&lt;/FONT&gt;&lt;FONT color=#808080&gt;,&lt;/FONT&gt;100&lt;FONT color=#808080&gt;,&lt;/FONT&gt;318&lt;FONT color=#808080&gt;,&lt;/FONT&gt;100&lt;FONT color=#808080&gt;,&lt;/FONT&gt;318&lt;FONT color=#808080&gt;,&lt;/FONT&gt;0&lt;FONT color=#808080&gt;,&lt;/FONT&gt;&lt;FONT color=#ff0000&gt;'20090101'&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#808080&gt;)&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;as&lt;/FONT&gt; T&lt;FONT color=#808080&gt;(&lt;/FONT&gt;PurchaseOrderID&lt;FONT color=#808080&gt;,&lt;/FONT&gt;DueDate&lt;FONT color=#808080&gt;,&lt;/FONT&gt;OrderQty&lt;FONT color=#808080&gt;,&lt;/FONT&gt;ProductID&lt;FONT color=#808080&gt;,&lt;/FONT&gt;UnitPrice&lt;FONT color=#808080&gt;,&lt;/FONT&gt;ReceivedQty&lt;FONT color=#808080&gt;,&lt;/FONT&gt;RejectedQty&lt;FONT color=#808080&gt;,&lt;/FONT&gt;ModifiedDate&lt;FONT color=#808080&gt;)&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;on&lt;/FONT&gt; T&lt;FONT color=#808080&gt;.&lt;/FONT&gt;PurchaseOrderID &lt;FONT color=#808080&gt;=&lt;/FONT&gt; P&lt;FONT color=#808080&gt;.&lt;/FONT&gt;PurchaseOrderID&lt;BR&gt;&lt;FONT color=#0000ff&gt;when&lt;/FONT&gt; &lt;FONT color=#808080&gt;matched&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;then&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;&amp;nbsp; update&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;set&lt;/FONT&gt; ModifiedDate &lt;FONT color=#808080&gt;=&lt;/FONT&gt; T&lt;FONT color=#808080&gt;.&lt;/FONT&gt;ModifiedDate&lt;BR&gt;&lt;FONT color=#0000ff&gt;when&lt;/FONT&gt; &lt;FONT color=#808080&gt;not&lt;/FONT&gt; &lt;FONT color=#808080&gt;matched&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;by&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;target&lt;/FONT&gt; &lt;FONT color=#808080&gt;and&lt;/FONT&gt; PurchaseOrderID &lt;FONT color=#808080&gt;&amp;lt;&lt;/FONT&gt; 0 &lt;FONT color=#0000ff&gt;then&lt;BR&gt;&amp;nbsp; &lt;/FONT&gt;&lt;FONT color=#0000ff&gt;insert &lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;/FONT&gt;PurchaseOrderID&lt;FONT color=#808080&gt;,&lt;/FONT&gt;DueDate&lt;FONT color=#808080&gt;,&lt;/FONT&gt;OrderQty&lt;FONT color=#808080&gt;,&lt;/FONT&gt;ProductID&lt;FONT color=#808080&gt;,&lt;/FONT&gt;UnitPrice&lt;FONT color=#808080&gt;,&lt;/FONT&gt;ReceivedQty&lt;FONT color=#808080&gt;,&lt;/FONT&gt;RejectedQty&lt;FONT color=#808080&gt;,&lt;/FONT&gt;ModifiedDate&lt;FONT color=#808080&gt;)&lt;BR&gt;&amp;nbsp; &lt;/FONT&gt;&lt;FONT color=#0000ff&gt;values &lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;/FONT&gt;3&lt;FONT color=#808080&gt;,&lt;/FONT&gt;&lt;FONT color=#ff0000&gt;'20010715'&lt;/FONT&gt;&lt;FONT color=#808080&gt;,&lt;/FONT&gt;100&lt;FONT color=#808080&gt;,&lt;/FONT&gt;318&lt;FONT color=#808080&gt;,&lt;/FONT&gt;100&lt;FONT color=#808080&gt;,&lt;/FONT&gt;318&lt;FONT color=#808080&gt;,&lt;/FONT&gt;0&lt;FONT color=#808080&gt;,&lt;/FONT&gt;&lt;FONT color=#ff0000&gt;'20090101'&lt;/FONT&gt;&lt;FONT color=#808080&gt;);&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;select&lt;/FONT&gt; &lt;FONT color=#808080&gt;*&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;From&lt;/FONT&gt; GrandTotal&lt;BR&gt;&lt;FONT color=#0000ff&gt;rollback&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;tran&lt;/FONT&gt;&lt;FONT color=#808080&gt;;&lt;BR&gt;&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;Oops.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;MERGE is only beginning to get&amp;nbsp;used, and for a variety of triggers, a too-large @@rowcount won't cause a problem. But I think the number of people who might get caught by this problem will grow.&lt;/P&gt;
&lt;P&gt;Don't use @@rowcount in triggers, unless you're certain it doesn't cause problems if it's higher than the real rowcount you want (which might be zero). As an alternative, Itzik suggested to me this (for INSERT; the others are similar):&lt;/P&gt;&lt;FONT color=#0000ff&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;declare&lt;/FONT&gt; @rc &lt;FONT color=#0000ff&gt;int&lt;/FONT&gt;&lt;FONT color=#808080&gt;;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;with&lt;/FONT&gt; Two &lt;FONT color=#0000ff&gt;as &lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;select&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;top &lt;/FONT&gt;&lt;FONT color=#808080&gt;(&lt;/FONT&gt;2&lt;FONT color=#808080&gt;)&lt;/FONT&gt; &lt;FONT color=#808080&gt;*&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;from&lt;/FONT&gt; inserted&lt;FONT color=#808080&gt;)&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#0000ff&gt;select&lt;/FONT&gt; @rc &lt;FONT color=#808080&gt;=&lt;/FONT&gt; &lt;FONT color=#ff00ff&gt;count&lt;/FONT&gt;&lt;FONT color=#808080&gt;(*)&lt;/FONT&gt; &lt;FONT color=#0000ff&gt;from&lt;/FONT&gt; Two&lt;FONT color=#808080&gt;;&lt;/FONT&gt;&lt;/P&gt;&lt;FONT color=#808080&gt;&lt;/FONT&gt;&lt;/DIV&gt;The value of @rc will then be 0, 1, or 2, depending on whether 0, 1, or more than 1 rows were inserted.&lt;/DIV&gt;
&lt;P&gt;Steve Kass&lt;BR&gt;&lt;A href="http://www.stevekass.com/"&gt;http://www.stevekass.com&lt;/A&gt;&lt;/P&gt;&lt;/SPAN&gt;&lt;img src="http://sqlblog.com/aggbug.aspx?PostID=13623" width="1" height="1"&gt;</content><author><name>skass</name><uri>http://sqlblog.com/members/skass.aspx</uri></author><category term="MERGE" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/MERGE/default.aspx" /><category term="SQL Server 2008" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/SQL+Server+2008/default.aspx" /><category term="Triggers" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/Triggers/default.aspx" /><category term="@@rowcount" scheme="http://sqlblog.com/blogs/steve_kass/archive/tags/_40004000_rowcount/default.aspx" /></entry></feed>
