<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>SQL Programmability &amp; API Development Team Blog : SQL Server 2000</title><link>http://blogs.msdn.com/sqlprogrammability/archive/tags/SQL+Server+2000/default.aspx</link><description>Tags: SQL Server 2000</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Predicate ordering is not guaranteed</title><link>http://blogs.msdn.com/sqlprogrammability/archive/2006/05/12/596401.aspx</link><pubDate>Fri, 12 May 2006 22:40:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:596401</guid><dc:creator>Jun Fang</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/sqlprogrammability/comments/596401.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlprogrammability/commentrss.aspx?PostID=596401</wfw:commentRss><description>&lt;P&gt;A typical programmer may expect that the predicates are always evaluated in the order that they are specified, but this is not true in database systems.&lt;/P&gt;
&lt;P&gt;For example, for the following clause,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;where col11 = 5 and convert(int, col2) = 100&lt;/P&gt;
&lt;P&gt;programmers may think col11 = 5 is always evaluated first, but this is not guaranteed. Query Optimizer may choose to first evaluate the second predicate, convert(int, col2) = 100. In fact, predicates may be pushed down the query tree, and not evaluated at the same time.&lt;/P&gt;
&lt;P&gt;Such reordering is generally benign, as the row has to satisfy both conditions to qualify. But it may make a difference if the second predicate would cause an error if the first condition is not met. The following example demonstrates this. &lt;/P&gt;
&lt;P&gt;Here we have a table with category and value both as string columns. From business logic, we know that when category is 'ID', value always contains a string with an integer ID. Therefore, we create a view, ID_View, that only shows the rows with category 'ID', and in the view, we will convert the value column to integer, and project as ID column.&lt;/P&gt;
&lt;P&gt;-- Create table&lt;BR&gt;create table dbo.test( &lt;BR&gt;id int not null primary key, &lt;BR&gt;category varchar(30) not null, &lt;BR&gt;value varchar(50) not null,&lt;BR&gt;name varchar(30)) &lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;-- Populate this table with data&lt;BR&gt;-- The logic is that when category is 'ID', value is a string of integer ID&lt;BR&gt;insert into dbo.test&lt;BR&gt;values (1, 'Text', 'Hello world', 'foo')&lt;BR&gt;insert into dbo.test&lt;BR&gt;values (2, 'ID', '123', 'bar')&lt;BR&gt;go&lt;BR&gt;&amp;nbsp;&lt;BR&gt;-- Create a view that only shows the rows that has category 'ID', &lt;BR&gt;-- and in that case, convert the value to an integer ID&lt;BR&gt;create view dbo.ID_view as &lt;BR&gt;select convert(int, value) ID, name from dbo.test&lt;BR&gt;where category = 'ID'&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- this will show the rows where category is 'ID'&lt;BR&gt;select * from dbo.ID_view&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;-- this will cause an error&lt;BR&gt;select * from dbo.ID_view&lt;BR&gt;where ID = 123&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;Selecting all rows from the view works perfectly fine. However, when we try to select from the view where ID is a certain value, 123, we get an runtime error:&lt;/P&gt;
&lt;P&gt;Server: Msg 245, Level 16, State 1, Line 1&lt;BR&gt;Syntax error converting the varchar value 'Hello world' to a column of data type int.&lt;/P&gt;
&lt;P&gt;The reason is that ID = 123 is expanded into convert(int, value) = 123, and it gets evaluated before the predicate category = 'ID'. Therefore, for the first row, with category as 'Text', and value as 'Hellow world', the conversion from value to int caused the runtime error.&lt;/P&gt;
&lt;P&gt;In this particular example, there is no advantage of evaluating which predicate first, so Query Optimizer could choose either order. In other cases, it may be more efficient to evaluate the second predicate first, and Query Optimizer has no idea if the predicate evaluation would cause a runtime error, since it doesn't know the correlation between the two columns.&lt;/P&gt;
&lt;P&gt;Note that the error happens on SQL 2000, but the query works fine on SQL 2005 because Query Optimizer happens to choose the other order. However, there is no guarantee that it won't change again in the future.&lt;/P&gt;
&lt;P&gt;The correct way to implement such correlation is to use a CASE expression.&lt;/P&gt;
&lt;P&gt;create view dbo.ID_view_new as &lt;BR&gt;select case when category = 'ID' then convert(int, value) else NULL end ID, name from dbo.test&lt;BR&gt;where category = 'ID'&lt;BR&gt;go&lt;BR&gt;-- this will works fine&lt;BR&gt;select * from dbo.ID_view_new&lt;BR&gt;where ID = 123&lt;BR&gt;go&lt;/P&gt;
&lt;P&gt;In the view definition, even though the filter indicates all rows will have category 'ID', in the select list, we still use the CASE expression to check again and return NULL otherwise. This can help prevent the error even with predicate reordering.&lt;/P&gt;
&lt;P&gt;In a word, the order of evaluation for predicates is never guaranteed, so application logic should not depend on such order. If a predicate depends on other predicates and may cause runtime error if other conditions are not met, application&amp;nbsp;should use CASE expression to make it work in any usage.&lt;BR&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=596401" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/Misc.+Issues/default.aspx">Misc. Issues</category><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/SQL+Server+2005/default.aspx">SQL Server 2005</category><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/SQL+Server+2000/default.aspx">SQL Server 2000</category></item><item><title>An article on FOR XML in Microsoft SQL Server 2000 and 2005</title><link>http://blogs.msdn.com/sqlprogrammability/archive/2006/04/13/576104.aspx</link><pubDate>Fri, 14 Apr 2006 01:04:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:576104</guid><dc:creator>ekogan</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/sqlprogrammability/comments/576104.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlprogrammability/commentrss.aspx?PostID=576104</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt;I just posted an article &lt;/SPAN&gt;&lt;A HREF="/sqlprogrammability/articles/576095.aspx"&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt;What does server side FOR XML return?&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN style="mso-ansi-language: EN-US"&gt; &lt;SPAN lang=EN-US&gt;(&lt;A HREF="/sqlprogrammability/articles/576095.aspx"&gt;http://blogs.msdn.com/sqlprogrammability/articles/576095.aspx&lt;/A&gt;) which gives some details of the design and performance characteristics of various FOR XML flavors.&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt;I also added links to XML whitepapers and publications on the design of XML features in Microsoft SQL Server 2005 to the links section of the main &lt;/SPAN&gt;&lt;A HREF="/sqlprogrammability/default.aspx"&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt;SQL Programmability &amp;amp; API Development Team Blog&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt; page (&lt;A HREF="/sqlprogrammability/default.aspx"&gt;http://blogs.msdn.com/sqlprogrammability/default.aspx&lt;/A&gt;).&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt;&lt;FONT style="BACKGROUND-COLOR: #ffffff"&gt;&lt;FONT color=#000080&gt;Best regards,&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt;&lt;FONT style="BACKGROUND-COLOR: #ffffff"&gt;&lt;FONT color=#000080&gt;Eugene Kogan&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt;&lt;FONT style="BACKGROUND-COLOR: #ffffff"&gt;&lt;FONT color=#000080&gt;Technical Lead&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN lang=EN-US style="mso-ansi-language: EN-US"&gt;&lt;FONT style="BACKGROUND-COLOR: #ffffff"&gt;&lt;FONT color=#000080&gt;Microsoft SQL Server Relational Engine&lt;o:p&gt;&lt;/o:p&gt;&lt;/FONT&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=576104" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/XML/default.aspx">XML</category><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/SQL+Server+2005/default.aspx">SQL Server 2005</category><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/SQL+Server+2000/default.aspx">SQL Server 2000</category></item><item><title>Sorting undefined characters in Unicode and/or Windows collation</title><link>http://blogs.msdn.com/sqlprogrammability/archive/2006/04/07/570397.aspx</link><pubDate>Fri, 07 Apr 2006 02:21:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:570397</guid><dc:creator>Jun Fang</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/sqlprogrammability/comments/570397.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlprogrammability/commentrss.aspx?PostID=570397</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;When comparing two Unicode strings in non-binary collations, SQL Server uses a library that is essentially same as the Windows API CompareStringW. It defines a weight for each recognized character, and then use the weights to compare characters. However, not all code points are defined in the sorting library. They may be undefined because:&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;1) The code point is not defined in Unicode standard.&lt;BR&gt;2) The code point is defined in Unicode standard, but not defined by Windows yet. It takes time and effort to define linguistic sorting semantics for new characters. Windows team typically needs to work with local standard body and/or regional PMs to define sorting rules for new characters. They add new character support in every release, and try to catch up. Some characters may have font defined, therefore could be correctly displayed, but still not defined in terms of comparison. For example, NCHAR(13144) - NCHAR(13174).&lt;BR&gt;3) The code point is defined in Windows, but not defined in SQL Server yet. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;Windows NLS team has decided that undefined characters are ignored during string comparison, partly because there is no real good way to compare them against other defined characters. SQL Server inherited this semantics. This does cause some confusing behavior.&amp;nbsp;See below examples.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;declare @undefined_char1 nvarchar(10), @undefined_char2 nvarchar(10)&lt;BR&gt;set @undefined_char1 = nchar(0x0000)&lt;BR&gt;set @undefined_char2 = nchar(13144)&lt;BR&gt;select 'Undefine characters compare equal to empty string'&lt;BR&gt;where @undefined_char1 = ''&lt;BR&gt;select 'All undefine characters compare equal'&lt;BR&gt;where @undefined_char1 = @undefined_char2&lt;BR&gt;go&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;create table t (c nvarchar(10))&lt;BR&gt;go&lt;BR&gt;create unique index it on t(c)&lt;BR&gt;go&lt;BR&gt;-- first insert succeeds, but second insert fails with duplicate key error.&lt;BR&gt;insert t values (nchar(0x0000))&lt;BR&gt;insert t values (nchar(13144))&lt;BR&gt;go&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;As you can see, since all undefined characters compare equal, they could cause duplicate key errors. Similarly, if you create one table with name of an undefined character, and then try to create another table with another undefined character, the second table creation would fail due to duplicate names, even though the code points of the two undefined characters are different. This could also cause confusing results in string matching builtins such as CHARINDEX, PATINDEX, or LIKE.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;While these results seem confusing, the basic rule is actually very simple, i.e., undefined characters are ignored during comparison and string matching. Once you understand and remember this rule, the behavior should be easy to understand. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;There have been arguments whether undefined characters should be ignored. Since this is the behavior on Windows platform, and there is not a definitely better way to sort them, and for backwards compatibility, we are going to maintain this behavior. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 10pt"&gt;If your app needs to work with these undefined characters and expect to treat them as regular characters, you can use binary collation. In binary collation, comparison is done purely based on code points, not linguistic rules, so there is no notion about defined vs. undefined.&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=570397" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/Sorting/default.aspx">Sorting</category><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/SQL+Server+2005/default.aspx">SQL Server 2005</category><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/SQL+Server+2000/default.aspx">SQL Server 2000</category><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/Native+Types+and+Methods/default.aspx">Native Types and Methods</category></item><item><title>Multiplication and Division with Numerics</title><link>http://blogs.msdn.com/sqlprogrammability/archive/2006/03/29/564110.aspx</link><pubDate>Wed, 29 Mar 2006 20:21:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:564110</guid><dc:creator>mathh</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/sqlprogrammability/comments/564110.aspx</comments><wfw:commentRss>http://blogs.msdn.com/sqlprogrammability/commentrss.aspx?PostID=564110</wfw:commentRss><description>&lt;FONT size=2&gt;
&lt;P&gt;It can be surprising to see certain results when doing numeric arithmetic:&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;&lt;FONT face="Courier New"&gt;declare @num1 numeric(38,10)&lt;BR&gt;declare @num2 numeric(38,10)&lt;BR&gt;set @num1 = .0000006&lt;BR&gt;set @num2 = 1.0&lt;BR&gt;select cast( @num1 * @num2 as numeric(38,10))&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;Yields:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.0000010000&lt;/P&gt;
&lt;P&gt;Instead of:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.0000006000&lt;/P&gt;
&lt;P&gt;&lt;BR&gt;Why?&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;Well, Books Online (see Precision, Scale, and Length) dictates the following rule for numeric arithmetics:&lt;/P&gt;&lt;/FONT&gt;
&lt;TABLE cellSpacing=1 cellPadding=0 width=623 border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD vAlign=center width="40%"&gt;&lt;B&gt;
&lt;P align=center&gt;Operation &lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="39%"&gt;&lt;B&gt;
&lt;P align=center&gt;Result precision &lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="21%"&gt;&lt;B&gt;
&lt;P align=center&gt;Result scale * &lt;/B&gt;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=center width="40%"&gt;
&lt;P&gt;e1 + e2&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="39%"&gt;
&lt;P&gt;max(s1, s2) + max(p1-s1, p2-s2) + 1&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="21%"&gt;
&lt;P&gt;max(s1, s2)&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=center width="40%"&gt;
&lt;P&gt;e1 - e2&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="39%"&gt;
&lt;P&gt;max(s1, s2) + max(p1-s1, p2-s2) + 1&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="21%"&gt;
&lt;P&gt;max(s1, s2)&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=center width="40%"&gt;
&lt;P&gt;e1 * e2&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="39%"&gt;
&lt;P&gt;p1 + p2 + 1&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="21%"&gt;
&lt;P&gt;s1 + s2&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=center width="40%"&gt;
&lt;P&gt;e1 / e2&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="39%"&gt;
&lt;P&gt;p1 - s1 + s2 + max(6, s1 + p2 + 1)&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="21%"&gt;
&lt;P&gt;max(6, s1 + p2 + 1)&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD vAlign=center width="40%"&gt;
&lt;P&gt;e1 { UNION | EXCEPT | INTERSECT } e2&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="39%"&gt;
&lt;P&gt;max(s1, s2) + max(p1-s1, p2-s2)&lt;/P&gt;&lt;/TD&gt;
&lt;TD vAlign=center width="21%"&gt;
&lt;P&gt;max(s1, s2)&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;FONT size=2&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;In this case, the multiplication result precision and scale are computed as follows:&lt;/P&gt;
&lt;P&gt;Precision = P1 + P2 + 1 = 38 + 38 + 1 = 77&lt;/P&gt;
&lt;P&gt;Scale = S1 + S2 = 10 + 10 = 20&lt;/P&gt;
&lt;P&gt;So conceptually, the result should be numeric(77, 20), which isn't allowed. This is where the fine prints come in:&lt;/P&gt;
&lt;P&gt;* The result precision and scale have an absolute maximum of 38. When a result precision is greater than 38, the corresponding scale is reduced to prevent the integral part of a result from being truncated.&lt;/P&gt;
&lt;P&gt;Books Online currently doesn't go into the specifics on how such truncation is performed. &lt;/P&gt;
&lt;P&gt;Since the precision is higher than 38, we try to avoid truncating the integral part of the value by reducing the scale (thus truncating the decimal part of the value instead). How much scale should be sacrificed? There is no right answer. If we preserve too much, and the result of the multiplication of large numbers will be way off. If we preserve too little, multiplication of small numbers becomes an issue.&lt;/P&gt;
&lt;P&gt;In SQL Server 2005 RTM (and previous versions), we decided preserve a minimum scale of 6 in both multiplication and division. So our numeric(77,20) is truncated as numeric(38,6), and then is then casted as numeric(38,10). However at this point it is too late, and some data has been lost. This explains the result you would see in the previous expression.&lt;/P&gt;
&lt;P&gt;Because of this, it is important to try to minimally quantify the precision and scale of the operands involved in multiplication and division. In this case:&lt;/P&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;declare @num1 numeric(18,10)&lt;BR&gt;declare @num2 numeric(18,10)&lt;BR&gt;set @num1 = .0000006&lt;BR&gt;set @num2 = 1.0&lt;BR&gt;select cast( @num1 * @num2 as numeric(38,10))&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;&lt;FONT size=2&gt;
&lt;P&gt;The resulting type would be numeric(37,20). Since this type's precision and scale does not exceed our current limits, no implicit truncation is performed. We then cast the result as numeric(38,10), which doesn't cause data loss in our case.&lt;/P&gt;
&lt;P&gt;If you cannot accurately type the values involved in multiplication and division, for example if they are procedure parameters that are called with wildly different values, you may want to look into approximate numeric types (float, real), or perhaps define your own very high capacity user defined exact numeric data type using the CLR.&lt;/P&gt;
&lt;P&gt;I hope this was useful. Let us know if there are particular topics you'd like to hear about!&lt;/P&gt;
&lt;P&gt;-Mat&lt;/P&gt;&lt;/FONT&gt;&lt;FONT size=2&gt;&lt;/FONT&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=564110" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/SQL+Server+2005/default.aspx">SQL Server 2005</category><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/SQL+Server+2000/default.aspx">SQL Server 2000</category><category domain="http://blogs.msdn.com/sqlprogrammability/archive/tags/Native+Types+and+Methods/default.aspx">Native Types and Methods</category></item></channel></rss>