<?xml version="1.0" encoding="iso-8859-1"?><!-- generator="b2evolution/4.0.3" -->
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Data Management - Author(s): Erik</title>
		<link>http://blogs.lessthandot.com/index.php/DataMgmt/</link>
		<atom:link rel="self" type="application/rss+xml" href="http://blogs.lessthandot.com/index.php/DataMgmt/?tempskin=_rss2" />
		<description></description>
		<language>en-GB</language>
		<docs>http://blogs.law.harvard.edu/tech/rss</docs>
		<admin:generatorAgent rdf:resource="http://b2evolution.net/?v=4.0.3"/>
		<ttl>60</ttl>
				<item>
			<title>Convenient ad-hoc bcp table loading</title>
			<link>http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/MSSQLServerAdmin/convenient-ad-hoc-bcp-table</link>
			<pubDate>Sat, 04 Feb 2012 00:00:00 +0000</pubDate>			<dc:creator>Erik</dc:creator>
			<category domain="main">Microsoft SQL Server Admin</category>
<category domain="alt">Microsoft SQL Server</category>			<guid isPermaLink="false">1617@http://blogs.lessthandot.com/</guid>
						<description>&lt;p&gt;Many times I am given an Excel file, or have a data source that makes it easy to paste into Excel, and I need to use the data in my database for a one-time purpose of updating or checking other data. It&#039;s not worth creating an SSIS package, and it&#039;s not even worth using a wizard in SSMS. So generally I use bcp as a very fast method.&lt;/p&gt;
&lt;p&gt;To do that, I quickly create a staging table in my database, then save the Excel file as tab-delimited.&lt;/p&gt;
&lt;p&gt;Then I have to go play with bcp and figure out the syntax yet again, since I don&#039;t do it often enough to have made it unthinkingly automatic. Recently I got tired of these repeated lookups and created the following batch file to help out:&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: courier new,courier;&quot;&gt;@echo off&lt;br /&gt;:top&lt;br /&gt;if .%1==. goto end&lt;br /&gt;echo Ready to import file to SqlServerName, DB DBName:&lt;br /&gt;echo&amp;#160; %1&lt;br /&gt;set /P tablename=Type destination table name and press Enter: &lt;br /&gt;osql -S SqlServerName -d DBName&lt;/span&gt;&lt;span style=&quot;font-family: courier new,courier;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: courier new,courier;&quot;&gt;-E -Q &quot;truncate table %tablename%&quot;&lt;br /&gt;bcp DBName.%tablename% in %1 -S SqlServername -T -c&lt;br /&gt;echo.&lt;br /&gt;shift&lt;br /&gt;goto top&lt;br /&gt;:end&lt;br /&gt;set tablename=&lt;br /&gt;pause&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Name the batch file &quot;SqlServerName DBName import replace (drop file).bat&quot;.&lt;/p&gt;
&lt;p&gt;Now in Windows Explorer, just drag any file you want to import to your database onto the batch file. When prompted, type in the schema and table name you want it loaded to, and press Enter. You&#039;ll get a nice pause to see what the result was so you can fix it if not successful. It even supports dropping multiple files, and you&#039;ll be asked for a destination table name for each file.&lt;/p&gt;
&lt;p&gt;If you find yourself needing to load a text file to a particular table over and over, just make a batch file specific to that text file, and you can drag-and-drop your imports super easily.&lt;/p&gt;
&lt;p&gt;You can of course customize the batch file to do anything you want. To prompt for server name, database name, username, password, or anything you like. And you won&#039;t have to look up the syntax for bcp one more blasted time!&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/MSSQLServerAdmin/convenient-ad-hoc-bcp-table&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://lessthandot.com/&quot;&gt;LessThanDot&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>Many times I am given an Excel file, or have a data source that makes it easy to paste into Excel, and I need to use the data in my database for a one-time purpose of updating or checking other data. It's not worth creating an SSIS package, and it's not even worth using a wizard in SSMS. So generally I use bcp as a very fast method.</p>
<p>To do that, I quickly create a staging table in my database, then save the Excel file as tab-delimited.</p>
<p>Then I have to go play with bcp and figure out the syntax yet again, since I don't do it often enough to have made it unthinkingly automatic. Recently I got tired of these repeated lookups and created the following batch file to help out:</p>
<p><span style="font-family: courier new,courier;">@echo off<br />:top<br />if .%1==. goto end<br />echo Ready to import file to SqlServerName, DB DBName:<br />echo&#160; %1<br />set /P tablename=Type destination table name and press Enter: <br />osql -S SqlServerName -d DBName</span><span style="font-family: courier new,courier;"> </span><span style="font-family: courier new,courier;">-E -Q "truncate table %tablename%"<br />bcp DBName.%tablename% in %1 -S SqlServername -T -c<br />echo.<br />shift<br />goto top<br />:end<br />set tablename=<br />pause</span></p>
<p>Name the batch file "SqlServerName DBName import replace (drop file).bat".</p>
<p>Now in Windows Explorer, just drag any file you want to import to your database onto the batch file. When prompted, type in the schema and table name you want it loaded to, and press Enter. You'll get a nice pause to see what the result was so you can fix it if not successful. It even supports dropping multiple files, and you'll be asked for a destination table name for each file.</p>
<p>If you find yourself needing to load a text file to a particular table over and over, just make a batch file specific to that text file, and you can drag-and-drop your imports super easily.</p>
<p>You can of course customize the batch file to do anything you want. To prompt for server name, database name, username, password, or anything you like. And you won't have to look up the syntax for bcp one more blasted time!</p><div class="item_footer"><p><small><a href="http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/MSSQLServerAdmin/convenient-ad-hoc-bcp-table">Original post</a> blogged on <a href="http://lessthandot.com/">LessThanDot</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/MSSQLServerAdmin/convenient-ad-hoc-bcp-table#comments</comments>
			<wfw:commentRss>http://blogs.lessthandot.com/index.php/DataMgmt/?tempskin=_rss2&#38;disp=comments&#38;p=1617</wfw:commentRss>
		</item>
				<item>
			<title>SQL Query Commenting/Uncommenting Quick Tip</title>
			<link>http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/sql-query-commenting-uncommenting-quick</link>
			<pubDate>Fri, 11 Dec 2009 17:28:37 +0000</pubDate>			<dc:creator>Erik</dc:creator>
			<category domain="alt">Database Programming</category>
<category domain="main">Microsoft SQL Server</category>			<guid isPermaLink="false">694@http://blogs.lessthandot.com/</guid>
						<description>&lt;p&gt;If you have multiple queries in one SQL query file, and you are switching around between which ones you want to run at any one time, there is an easy way to do this.&lt;/p&gt;

&lt;p&gt;The scenario I&#039;m thinking of is something like when you&#039;re solving a SQL puzzle/challenge and keep trying new ideas and query versions. You don&#039;t want to delete your old queries because they are useful for reference or to copy and paste parts of them, but you don&#039;t want to run them all the time. Especially during performance tweaking, you want to be able to quickly comment out the worst queries and keep pasting in new versions of the fastest queries.&lt;/p&gt;

&lt;p&gt;Normally this would require either highlighting entire queries to comment/uncomment them (Ctrl-Shift-C/Ctrl-Shift-U in Query Analyzer or Ctrl-K:Ctrl-C/Ctrl-K:Ctrl-U in SSMS); adding or removing /* and */ at the top and bottom of the query; or highlighting just the portions of the code that you want to run each time, which is a pain and can be complicated if you are using table variables since your initialization code at the top has to run each time.&lt;/p&gt;

&lt;p&gt;So try this!&lt;/p&gt;

&lt;p&gt;Put --/* at the top of your query and --*/ at the bottom:&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb60734&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;--/* Test Query #3 (Gorp Method)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; *&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; Blah&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHERE&lt;/span&gt; Gorp = &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;--*/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb60930&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Notice that the query is NOT commented out.&lt;/p&gt;

&lt;p&gt;Now, to toggle the whole query as commented or not, just uncomment the first line:&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb86282&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;/* Test Query #3 (Gorp Method)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;SELECT *&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;FROM Blah&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;WHERE Gorp = 1&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;--*/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb1535&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I just hit on this method yesterday and I&#039;m really enjoying it. It provides a natural place to put a query comment, you only have to put the block comments in once, and then you can use your comment/uncomment shortcuts on just a single line to toggle an entire block of code! Just keep in mind that the action IS reversed: you comment to uncomment and you uncomment to comment.&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/sql-query-commenting-uncommenting-quick&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://lessthandot.com/&quot;&gt;LessThanDot&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>If you have multiple queries in one SQL query file, and you are switching around between which ones you want to run at any one time, there is an easy way to do this.</p>

<p>The scenario I'm thinking of is something like when you're solving a SQL puzzle/challenge and keep trying new ideas and query versions. You don't want to delete your old queries because they are useful for reference or to copy and paste parts of them, but you don't want to run them all the time. Especially during performance tweaking, you want to be able to quickly comment out the worst queries and keep pasting in new versions of the fastest queries.</p>

<p>Normally this would require either highlighting entire queries to comment/uncomment them (Ctrl-Shift-C/Ctrl-Shift-U in Query Analyzer or Ctrl-K:Ctrl-C/Ctrl-K:Ctrl-U in SSMS); adding or removing /* and */ at the top and bottom of the query; or highlighting just the portions of the code that you want to run each time, which is a pain and can be complicated if you are using table variables since your initialization code at the top has to run each time.</p>

<p>So try this!</p>

<p>Put --/* at the top of your query and --*/ at the bottom:</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb28670'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb28670','cb19911'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb28670" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #00AF00;">--/* Test Query #3 (Gorp Method)</span></li><li style="" class="li2"><span style="color: #0000FF;">SELECT</span> *</li><li style="" class="li1"><span style="color: #0000FF;">FROM</span> Blah</li><li style="" class="li2"><span style="color: #0000FF;">WHERE</span> Gorp = <span style="color: #000;">1</span></li><li style="" class="li1"><span style="color: #00AF00;">--*/</span></li></ol></div><div id="cb19911" style="display: none; color: red;"></div></div></div>
<p>Notice that the query is NOT commented out.</p>

<p>Now, to toggle the whole query as commented or not, just uncomment the first line:</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb58256'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb58256','cb426'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb58256" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #00AF00;">/* Test Query #3 (Gorp Method)</span></li><li style="" class="li2"><span style="color: #00AF00;">SELECT *</span></li><li style="" class="li1"><span style="color: #00AF00;">FROM Blah</span></li><li style="" class="li2"><span style="color: #00AF00;">WHERE Gorp = 1</span></li><li style="" class="li1"><span style="color: #00AF00;">--*/</span></li></ol></div><div id="cb426" style="display: none; color: red;"></div></div></div>
<p>I just hit on this method yesterday and I'm really enjoying it. It provides a natural place to put a query comment, you only have to put the block comments in once, and then you can use your comment/uncomment shortcuts on just a single line to toggle an entire block of code! Just keep in mind that the action IS reversed: you comment to uncomment and you uncomment to comment.</p><div class="item_footer"><p><small><a href="http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/sql-query-commenting-uncommenting-quick">Original post</a> blogged on <a href="http://lessthandot.com/">LessThanDot</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/sql-query-commenting-uncommenting-quick#comments</comments>
			<wfw:commentRss>http://blogs.lessthandot.com/index.php/DataMgmt/?tempskin=_rss2&#38;disp=comments&#38;p=694</wfw:commentRss>
		</item>
				<item>
			<title>Undetectable Distributed Deadlocks</title>
			<link>http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/undetectable-distributed-deadlocks</link>
			<pubDate>Fri, 13 Nov 2009 22:59:13 +0000</pubDate>			<dc:creator>Erik</dc:creator>
			<category domain="alt">Database Programming</category>
<category domain="main">Microsoft SQL Server</category>			<guid isPermaLink="false">673@http://blogs.lessthandot.com/</guid>
						<description>&lt;p&gt;I believe I have discovered a deadlock situation that SQL Server is not able to detect, so a perpetual block occurs.&lt;/p&gt;

&lt;p&gt;A deadlock is nothing more than mutual blocking. Blocking is when a process is forced to wait for a resource while another process exclusively accesses it (where the exclusivity is managed through locks). Mutual blocking is when both processes have a lock on a resource the other is asking for. Neither can proceed, but neither will release its lock.&lt;/p&gt;

&lt;p&gt;Normally, when SQL server detects this kind of mutual block, it picks one process as the &quot;victim&quot; and kills it, rolling back its work. This also releases any locks it had and allows the other process to acquire its previously blocked request, resolving the deadlock.&lt;/p&gt;

&lt;p&gt;But what if the two resources in question are on separate servers? For SQL Server to detect deadlocks, it has to have enough information to see that a pattern of blocks is mutual.&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb121&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;--Query 1&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;UPDATE&lt;/span&gt; B&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; B.&lt;span style=&quot;color: #202020;&quot;&gt;Name&lt;/span&gt; = A.&lt;span style=&quot;color: #202020;&quot;&gt;Name&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;TableA A&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN LinkedServer.&lt;span style=&quot;color: #202020;&quot;&gt;DB1&lt;/span&gt;.&lt;span style=&quot;color: #202020;&quot;&gt;dbo&lt;/span&gt;.&lt;span style=&quot;color: #202020;&quot;&gt;TableB&lt;/span&gt; B &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; A.&lt;span style=&quot;color: #202020;&quot;&gt;ID&lt;/span&gt; = B.&lt;span style=&quot;color: #202020;&quot;&gt;ID&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;--Query 2&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;UPDATE&lt;/span&gt; B&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; B.&lt;span style=&quot;color: #202020;&quot;&gt;Name&lt;/span&gt; = A.&lt;span style=&quot;color: #202020;&quot;&gt;Name&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;LinkedServer.&lt;span style=&quot;color: #202020;&quot;&gt;DB1&lt;/span&gt;.&lt;span style=&quot;color: #202020;&quot;&gt;dbo&lt;/span&gt;.&lt;span style=&quot;color: #202020;&quot;&gt;TableB&lt;/span&gt; B&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN TableA A &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; B.&lt;span style=&quot;color: #202020;&quot;&gt;ID&lt;/span&gt; = A.&lt;span style=&quot;color: #202020;&quot;&gt;ID&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb52942&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, let&#039;s say that locks for these two queries are granted in this order: query 1 acquires a lock on TableA before Table B, but query 2 acquires a lock on TableB before TableA. Even though the example I&#039;m giving here may not be the greatest, the possibility is not so unlikely, and I&#039;m sure there are plenty of situations out in the wild where my suggested scenario is possible.&lt;/p&gt;

&lt;p&gt;Locks are not granted all at once, nor can one assume that the final lock used for an update is granted first. Many times a less exclusive lock is acquired and then the lock&#039;s exclusiveness is increased or specificity is broadened, and that&#039;s all that&#039;s required to cause a deadlock. See &lt;a href=http://www.sqlmag.com/article/articleid/95538/95538.html&gt;Deadlocks with Custom Sequence&lt;/a&gt; for one example of surprising deadlocks occurring because of an unusual transaction isolation level. &lt;/p&gt;

&lt;p&gt;Given the above hypothetical lock order, when each query&#039;s process requests a lock on the other table to perform its update, it will be blocked. But each server involved only has half the picture and can only see a simple block, without knowing it&#039;s mutual (because the other half is occurring on the other side of the linked server). So it is a perpetual mutual block and no deadlock is detected.&lt;/p&gt;

&lt;p&gt;The next time I am working heavily with linked servers you can be sure I&#039;ll be thinking about this and coming up with a way to test if such a &quot;distributed deadlock&quot; really can occur, and if so, what to do about it.&lt;/p&gt;

&lt;p&gt;In closing, I confess that it&#039;s possible that DTC could have provisions for sharing lock information, so perhaps a distributed deadlock will be properly detected. But I have my doubts about that.&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/undetectable-distributed-deadlocks&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://lessthandot.com/&quot;&gt;LessThanDot&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>I believe I have discovered a deadlock situation that SQL Server is not able to detect, so a perpetual block occurs.</p>

<p>A deadlock is nothing more than mutual blocking. Blocking is when a process is forced to wait for a resource while another process exclusively accesses it (where the exclusivity is managed through locks). Mutual blocking is when both processes have a lock on a resource the other is asking for. Neither can proceed, but neither will release its lock.</p>

<p>Normally, when SQL server detects this kind of mutual block, it picks one process as the "victim" and kills it, rolling back its work. This also releases any locks it had and allows the other process to acquire its previously blocked request, resolving the deadlock.</p>

<p>But what if the two resources in question are on separate servers? For SQL Server to detect deadlocks, it has to have enough information to see that a pattern of blocks is mutual.</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb55724'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb55724','cb76844'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb55724" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #00AF00;">--Query 1</span></li><li style="" class="li2"><span style="color: #0000FF;">UPDATE</span> B</li><li style="" class="li1"><span style="color: #0000FF;">SET</span> B.<span style="color: #202020;">Name</span> = A.<span style="color: #202020;">Name</span></li><li style="" class="li2"><span style="color: #0000FF;">FROM</span></li><li style="" class="li1">&nbsp; &nbsp;TableA A</li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">INNER</span> JOIN LinkedServer.<span style="color: #202020;">DB1</span>.<span style="color: #202020;">dbo</span>.<span style="color: #202020;">TableB</span> B <span style="color: #0000FF;">ON</span> A.<span style="color: #202020;">ID</span> = B.<span style="color: #202020;">ID</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #00AF00;">--Query 2</span></li><li style="" class="li1"><span style="color: #0000FF;">UPDATE</span> B</li><li style="" class="li2"><span style="color: #0000FF;">SET</span> B.<span style="color: #202020;">Name</span> = A.<span style="color: #202020;">Name</span></li><li style="" class="li1"><span style="color: #0000FF;">FROM</span></li><li style="" class="li2">&nbsp; &nbsp;LinkedServer.<span style="color: #202020;">DB1</span>.<span style="color: #202020;">dbo</span>.<span style="color: #202020;">TableB</span> B</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">INNER</span> JOIN TableA A <span style="color: #0000FF;">ON</span> B.<span style="color: #202020;">ID</span> = A.<span style="color: #202020;">ID</span></li></ol></div><div id="cb76844" style="display: none; color: red;"></div></div></div>

<p>Now, let's say that locks for these two queries are granted in this order: query 1 acquires a lock on TableA before Table B, but query 2 acquires a lock on TableB before TableA. Even though the example I'm giving here may not be the greatest, the possibility is not so unlikely, and I'm sure there are plenty of situations out in the wild where my suggested scenario is possible.</p>

<p>Locks are not granted all at once, nor can one assume that the final lock used for an update is granted first. Many times a less exclusive lock is acquired and then the lock's exclusiveness is increased or specificity is broadened, and that's all that's required to cause a deadlock. See <a href=http://www.sqlmag.com/article/articleid/95538/95538.html>Deadlocks with Custom Sequence</a> for one example of surprising deadlocks occurring because of an unusual transaction isolation level. </p>

<p>Given the above hypothetical lock order, when each query's process requests a lock on the other table to perform its update, it will be blocked. But each server involved only has half the picture and can only see a simple block, without knowing it's mutual (because the other half is occurring on the other side of the linked server). So it is a perpetual mutual block and no deadlock is detected.</p>

<p>The next time I am working heavily with linked servers you can be sure I'll be thinking about this and coming up with a way to test if such a "distributed deadlock" really can occur, and if so, what to do about it.</p>

<p>In closing, I confess that it's possible that DTC could have provisions for sharing lock information, so perhaps a distributed deadlock will be properly detected. But I have my doubts about that.</p><div class="item_footer"><p><small><a href="http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/undetectable-distributed-deadlocks">Original post</a> blogged on <a href="http://lessthandot.com/">LessThanDot</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/undetectable-distributed-deadlocks#comments</comments>
			<wfw:commentRss>http://blogs.lessthandot.com/index.php/DataMgmt/?tempskin=_rss2&#38;disp=comments&#38;p=673</wfw:commentRss>
		</item>
				<item>
			<title>Including an Aggregated Column's Related Values</title>
			<link>http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/including-an-aggregated-column-s-related</link>
			<pubDate>Sat, 18 Jul 2009 04:51:05 +0000</pubDate>			<dc:creator>Erik</dc:creator>
			<category domain="main">Microsoft SQL Server</category>			<guid isPermaLink="false">528@http://blogs.lessthandot.com/</guid>
						<description>&lt;p&gt;In this co-authored blog post, &lt;a href=&quot;http://forum.lessthandot.com/memberlist.php?mode=viewprofile&amp;amp;u=314&quot;&gt;Naomi&lt;/a&gt; and I will present six different solutions to the commonly experienced query problem of how to include an aggregated column&#039;s related values - values from the same row in the group that provided the displayed value.&lt;/p&gt;

&lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;It&#039;s a fairly simple query to select the maximum date for each group in a GROUP BY query. You just throw in a Max() on the date column and then GROUP BY the other columns. For example,&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb87646&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;CustomerID,&lt;br /&gt;&amp;nbsp; &amp;nbsp;LastOrderDate = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;OrderDate&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; Orders&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;GROUP&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; CustomerID&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb34033&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;But a common query need is to include other column values from the same row as the most recent date. Unfortunately, putting aggregates on other columns doesn&#039;t work:&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb39779&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;CustomerID,&lt;br /&gt;&amp;nbsp; &amp;nbsp;LastOrderDate = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;OrderDate&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;LastSubTotal = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;SubTotal&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #00AF00;&quot;&gt;-- wrong: won&#039;t be the subtotal from Max(OrderDate), but the greatest order total ever placed by this customer.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; Orders&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;GROUP&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; CustomerID&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb34781&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It&#039;s almost like you need some kind of Max(OrderDate-&gt;SubTotal).&lt;/p&gt;

&lt;p&gt;Note that the desired results are fairly easy in MS Access using the aggregate functions Last and First:&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb57841&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;CustomerID,&lt;br /&gt;&amp;nbsp; &amp;nbsp;LastOrderDate = &lt;span style=&quot;color: #0000FF;&quot;&gt;Last&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;OrderDate&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;SubTotal = &lt;span style=&quot;color: #0000FF;&quot;&gt;Last&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;SubTotal&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; Orders&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;GROUP&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; CustomerID&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;ORDER&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; OrderDate&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb91201&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What happens in Access is that the Last() aggregate combines with the ORDER BY clause to select values from the row containing the most recent Order Date.&lt;/p&gt;

&lt;p&gt;However, these functions are not available in SQL Server, likely because the query engine only does ordering at the very end, after GROUP BY and HAVING are processed. While this may seem like a defect, it is really a deliberate design trade-off, with compensations elsewhere in the engine.&lt;/p&gt;

&lt;h2&gt;Test Case&lt;/h2&gt;

&lt;p&gt;In order to have enough data to make results significant and also to let others run the same queries against the same data, we are going to use the AdventureWorks sample database.&lt;/p&gt;

&lt;p&gt;In our scenario, we want to show customers&#039; account numbers along with the date and subtotal of their most recent order. We&#039;re keeping it simple for clarity, but note that you can include as many columns as you like. In a later installment we&#039;ll do these same queries with more columns and different scenarios, and will expand on some of the queries a bit. We&#039;ll also discuss performance to help you select between them.&lt;/p&gt;

&lt;p&gt;Note that the aggregate doesn&#039;t have to be on a date. Perhaps you want to know the date of the largest dollar value order per customer. In this case, you&#039;d be doing a Max() on the order value instead of a date, and you would most certainly run into duplicates. Keep this in mind when reading below and when developing your own queries.&lt;/p&gt;

&lt;p&gt;The basic query we&#039;ll be working with is:&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb61059&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;C.&lt;span style=&quot;color: #202020;&quot;&gt;AccountNumber&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;LastOrderDate = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;O.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;Sales.&lt;span style=&quot;color: #202020;&quot;&gt;Customer&lt;/span&gt; C&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt; O &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; C.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb29169&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What we want to do is also return the Subtotal value from the same row as the LastOrderDate.&lt;/p&gt;

&lt;h3&gt;Some Approaches to the Problem&lt;/h3&gt;

&lt;p&gt;We know of only a few basic approaches to the problem:&lt;/p&gt;

&lt;div&gt;&lt;p&gt;- &lt;strong&gt;Key Search&lt;/strong&gt; -- use the LastOrderDate column as a key (along with customer AccountNumber) to locate the correct rows in the OrderHeader table. This requires an extra join and also the key isn&#039;t unique, so we might have to perform another Max() on a unique column and join another time, with the new column added to the key.&lt;/p&gt;

&lt;p&gt;- &lt;strong&gt;Number and Filter&lt;/strong&gt; -- select all rows from OrderHeader, and number them in a way exploitable to correctly filter out unwanted rows. Observe that this won&#039;t require hitting the table again, but it could use a lot of extra resources to temporarily materialize more data. Skipping over obvious poor choices such as a temp table with an ordered update or a cursor, options might be a windowing function (SQL 2005 and up) or a temp table with an identity column (SQL 2000).&lt;/p&gt;

&lt;p&gt;- &lt;strong&gt;Simulate MS Access&lt;/strong&gt; -- simulate how MS Access works somehow, getting only the data we need in a single table access (seek or scan). Let&#039;s imagine how the SQL engine already performs a Max. As it touches each row, it must store the intermediate value that is the best candidate so far for all the seen values. And it has to have one of these per group, per column. All that is needed is that every time it writes the Max() candidate into its temporary storage, it also writes the extra column we want into the same data.&lt;/p&gt;

&lt;p&gt;How could we do this ourselves? We need to ORDER BY OrderDate but actually yield SubTotal. SubTotal clearly won&#039;t sort in the correct order by itself. Remembering Max(OrderDate-&gt;SubTotal), what if it wasn&#039;t by itself, and somehow contained the OrderDate, too, to make it sort properly? So here we have an idea about packing both columns into a single value that sorts correctly yet can still be used to get the SubTotal back out. When the engine does its Max() bit as usual on the date and stores the best candidate, it will also be forced to store the other value at the same time (which we can extract later).&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;So let&#039;s use those ideas and turn them into real queries. Unless otherwise stated, queries will work with SQL Server 2000.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;Key Search&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;1. Correlated Subquery&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Relies on unique order dates to avoid selecting multiple rows per customer.&lt;/li&gt;
  &lt;li&gt;Correlated subqueries perform well with small datasets and badly with large datasets (though better with SQL 2005 and 2008 because they can sometimes get converted to real joins).&lt;/li&gt;
  &lt;li&gt;Performance degrades geometrically as rows increase.&lt;/li&gt;
  &lt;li&gt;Does not handle NULLs correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb40560&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;C.&lt;span style=&quot;color: #202020;&quot;&gt;AccountNumber&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O.&lt;span style=&quot;color: #202020;&quot;&gt;SubTotal&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;Sales.&lt;span style=&quot;color: #202020;&quot;&gt;Customer&lt;/span&gt; C&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt; O &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; C.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; &lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHERE&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;O.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt; = &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #FF00FF;&quot;&gt;Max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;OrderDate&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; SalesOrderHeader O2&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;WHERE&lt;/span&gt; O2.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb97184&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;


&lt;p&gt;Another version of correlated subquery which sometimes performs much better is&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb33022&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;C.&lt;span style=&quot;color: #202020;&quot;&gt;AccountNumber&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O.&lt;span style=&quot;color: #202020;&quot;&gt;SubTotal&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;Sales.&lt;span style=&quot;color: #202020;&quot;&gt;Customer&lt;/span&gt; C&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt; O &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; C.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; &lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHERE&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;O.&lt;span style=&quot;color: #202020;&quot;&gt;OrderID&lt;/span&gt; = &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;top&lt;/span&gt; &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; OrderID &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; SalesOrderHeader O2&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;WHERE&lt;/span&gt; O2.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;order&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;by&lt;/span&gt; O2.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;Desc&lt;/span&gt;, O2.&lt;span style=&quot;color: #202020;&quot;&gt;OrderID&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb24237&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Another variation of this query is (suggested by Alejandro Mesa (Hunchback) in this &lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/0217ddf4-bcab-4f2b-a81c-70841753cb23&quot;&gt;MSDN thread&lt;/a&gt;):&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb94755&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;C.&lt;span style=&quot;color: #202020;&quot;&gt;AccountNumber&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O1.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O1.&lt;span style=&quot;color: #202020;&quot;&gt;SubTotal&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;Sales.&lt;span style=&quot;color: #202020;&quot;&gt;Customer&lt;/span&gt; C&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt; O1 &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; C.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O1.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; &lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHERE&lt;/span&gt; not exists &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;select&lt;/span&gt; &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;from&lt;/span&gt; Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt; O2 &lt;span style=&quot;color: #0000FF;&quot;&gt;where&lt;/span&gt; O2.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O1.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; and O1.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt; &amp;lt; O2.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb80299&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note, that the first variation of this query may return duplicate rows, but the second will always return only one row per group (with the latest OrderID).&lt;/p&gt;

&lt;p&gt;The third variation of this query with NOT EXISTS will produce duplicates in case of the same date, but can also be easily adjusted to return only one row with the max OrderID:&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb79153&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;C.&lt;span style=&quot;color: #202020;&quot;&gt;AccountNumber&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O1.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O1.&lt;span style=&quot;color: #202020;&quot;&gt;SubTotal&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;Sales.&lt;span style=&quot;color: #202020;&quot;&gt;Customer&lt;/span&gt; C&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt; O1 &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; C.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O1.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; &lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHERE&lt;/span&gt; not exists &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;select&lt;/span&gt; &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;from&lt;/span&gt; Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt; O2 &lt;span style=&quot;color: #0000FF;&quot;&gt;where&lt;/span&gt; O2.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O1.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; and &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;O1.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt; &amp;lt; O2.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt; OR &lt;br /&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;O1.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt; = O2.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt; and O1.&lt;span style=&quot;color: #202020;&quot;&gt;OrderID&lt;/span&gt; &amp;lt; O2.&lt;span style=&quot;color: #202020;&quot;&gt;OrderID&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb84926&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;2. Derived Table&lt;/h3&gt;
&lt;p&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Relies on unique order dates to avoid selecting multiple rows per customer.&lt;/li&gt;
  &lt;li&gt;Performs better than the correlated subquery when querying a significant portion of all customers, but worse when only querying a few, since the last order date for every customer is always calculated.&lt;/li&gt;
  &lt;li&gt;Performance degrades linearly as rows increase.&lt;/li&gt;
  &lt;li&gt;Does not handle NULLs correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb57621&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;C.&lt;span style=&quot;color: #202020;&quot;&gt;AccountNumber&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O.&lt;span style=&quot;color: #202020;&quot;&gt;SubTotal&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;Sales.&lt;span style=&quot;color: #202020;&quot;&gt;Customer&lt;/span&gt; C&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt; O &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; C.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; &lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; CustomerID, LastOrderDate = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;OrderDate&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;GROUP&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; CustomerID&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; O2 &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O2.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; AND O.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt; = O2.&lt;span style=&quot;color: #202020;&quot;&gt;LastOrderDate&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb75075&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;h2&gt;Number and Filter&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;Windowing Functions&lt;/h3&gt;

&lt;p&gt;The windowing functions were introduced in SQL Server 2005, so the two queries below will not work in SQL Server 2000.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Will always return one row per customer. Using RANK() instead of ROW_NUMBER() will yield the same results as queries 1 and 2.&lt;/li&gt;
  &lt;li&gt;Easily supports not just 1 but &lt;em&gt;n&lt;/em&gt; rows per group.&lt;/li&gt;
  &lt;li&gt;Performance degrades fairly linearly as rows increase. The windowing functions are fast but huge rowsets can begin to bog them down.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;3. Windowing Function - Two Stages&lt;/h3&gt;
&lt;p&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;A common table expression is not needed, but is cleaner. The CTE query can be made into a derived table if desired.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb24013&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;WITH&lt;/span&gt; OrderData &lt;span style=&quot;color: #0000FF;&quot;&gt;AS&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; C.&lt;span style=&quot;color: #202020;&quot;&gt;AccountNumber&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; O.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; O.&lt;span style=&quot;color: #202020;&quot;&gt;SubTotal&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; Selector = &lt;span style=&quot;color: #FF00FF;&quot;&gt;ROW_NUMBER&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;OVER&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;PARTITION&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;ORDER&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; O.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; Sales.&lt;span style=&quot;color: #202020;&quot;&gt;Customer&lt;/span&gt; C&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt; O &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; C.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; &lt;br /&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; AccountNumber, OrderDate, SubTotal&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; OrderData&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHERE&lt;/span&gt; Selector = &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb32729&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3&gt;4. Windowing Function - One Stage&lt;/h3&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb59595&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;TOP&lt;/span&gt; &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;WITH&lt;/span&gt; TIES&lt;br /&gt;&amp;nbsp; &amp;nbsp;C.&lt;span style=&quot;color: #202020;&quot;&gt;AccountNumber&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O.&lt;span style=&quot;color: #202020;&quot;&gt;OrderDate&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;O.&lt;span style=&quot;color: #202020;&quot;&gt;SubTotal&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;Sales.&lt;span style=&quot;color: #202020;&quot;&gt;Customer&lt;/span&gt; C&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt; O &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; C.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; = O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; &lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;ORDER&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #FF00FF;&quot;&gt;ROW_NUMBER&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;OVER&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;PARTITION&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;by&lt;/span&gt; O.&lt;span style=&quot;color: #202020;&quot;&gt;CustomerID&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;ORDER&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; OrderDate &lt;span style=&quot;color: #0000FF;&quot;&gt;DESC&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb24838&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;Simulate MS Access&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;5. Compound Key, aka Packed Values&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Uses only one table access with a simple GROUP BY.&lt;/li&gt;
  &lt;li&gt;Naomi first learned this idea from &lt;a href=&quot;http://forum.foxclub.ru/read.php?32,177183,177232#msg-177232&quot;&gt;a Russian SQL FAQ&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Erik cooked up a similar idea in 2008.&lt;/li&gt;
  &lt;li&gt;This example uses a varchar column to hold the packed values, but be aware that converting to and from binary is faster than char (plus harder to use and more error-prone) and binary aggregation is faster. The crucial part is being able to faithfully extract the data that was put in.&lt;/li&gt;
  &lt;li&gt;This query has no problem with duplicates. It does effectively sort by the full compound value, so if multiple orders for the same customer can be on the same order date and you want some other column to determine which one is selected, it has to be included in the packed data.&lt;/li&gt;
  &lt;li&gt;As given, this query does not handle NULLs at all. A few strategic Coalesces can fix that.&lt;/li&gt;
  &lt;li&gt;There is no significant performance difference between unpacking one many-item compound value or many one-item compound values (though you&#039;d always include all columns needed for ordering).&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb49929&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;CustomerID,&lt;br /&gt;&amp;nbsp; &amp;nbsp;LastOrderDate,&lt;br /&gt;&amp;nbsp; &amp;nbsp;LastSubTotal = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;money&lt;/span&gt;, &lt;span style=&quot;color: #FF00FF;&quot;&gt;Substring&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;DateAndSubtotal, &lt;span style=&quot;color: #000;&quot;&gt;20&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;25&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;CustomerID,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;LastOrderDate = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;OrderDate&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DateAndSubtotal = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF00FF;&quot;&gt;convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, OrderDate, &lt;span style=&quot;color: #000;&quot;&gt;121&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;Convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, Subtotal&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; Sales.&lt;span style=&quot;color: #202020;&quot;&gt;SalesOrderHeader&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;GROUP&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; CustomerID&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; X&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb81963&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Isn&#039;t that cool? I don&#039;t advocate using it all the time, but when performance is bad and the trade-offs are worth it, do it.&lt;/p&gt;

&lt;p&gt;In closing, thank you for visiting. We hope this is useful to you. You might like to see the next installment &lt;a href=&quot;http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/including-an-aggregated-column-s-related-2&quot;&gt;Including an Aggregated Column&#039;s Related Values - Part 2&lt;/a&gt;, discussing this issue in further depth.&lt;/p&gt;

&lt;p&gt;Erik&lt;/p&gt;

&lt;p&gt;P.S. I would like to thank &lt;a href=&quot;http://forum.lessthandot.com/memberlist.php?mode=viewprofile&amp;amp;u=314&quot;&gt;Naomi&lt;/a&gt; for co-authoring this blog post with me. She did the heavy lifting of actually writing queries and testing their performance; I just fleshed out the explanations a bit.&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/including-an-aggregated-column-s-related&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://lessthandot.com/&quot;&gt;LessThanDot&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>In this co-authored blog post, <a href="http://forum.lessthandot.com/memberlist.php?mode=viewprofile&amp;u=314">Naomi</a> and I will present six different solutions to the commonly experienced query problem of how to include an aggregated column's related values - values from the same row in the group that provided the displayed value.</p>

<h2>Background</h2>

<p>It's a fairly simple query to select the maximum date for each group in a GROUP BY query. You just throw in a Max() on the date column and then GROUP BY the other columns. For example,</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb22766'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb22766','cb57527'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb22766" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;CustomerID,</li><li style="" class="li1">&nbsp; &nbsp;LastOrderDate = <span style="color: #FF00FF;">Max</span><span style="color: #808080;">&#40;</span>OrderDate<span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">FROM</span> Orders</li><li style="" class="li1"><span style="color: #0000FF;">GROUP</span> <span style="color: #0000FF;">BY</span> CustomerID</li></ol></div><div id="cb57527" style="display: none; color: red;"></div></div></div>
<p>But a common query need is to include other column values from the same row as the most recent date. Unfortunately, putting aggregates on other columns doesn't work:</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb33198'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb33198','cb70445'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb33198" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;CustomerID,</li><li style="" class="li1">&nbsp; &nbsp;LastOrderDate = <span style="color: #FF00FF;">Max</span><span style="color: #808080;">&#40;</span>OrderDate<span style="color: #808080;">&#41;</span>,</li><li style="" class="li2">&nbsp; &nbsp;LastSubTotal = <span style="color: #FF00FF;">Max</span><span style="color: #808080;">&#40;</span>SubTotal<span style="color: #808080;">&#41;</span> <span style="color: #00AF00;">-- wrong: won't be the subtotal from Max(OrderDate), but the greatest order total ever placed by this customer.</span></li><li style="" class="li1"><span style="color: #0000FF;">FROM</span> Orders</li><li style="" class="li2"><span style="color: #0000FF;">GROUP</span> <span style="color: #0000FF;">BY</span> CustomerID</li></ol></div><div id="cb70445" style="display: none; color: red;"></div></div></div>

<p>It's almost like you need some kind of Max(OrderDate->SubTotal).</p>

<p>Note that the desired results are fairly easy in MS Access using the aggregate functions Last and First:</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb67462'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb67462','cb78599'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb67462" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;CustomerID,</li><li style="" class="li1">&nbsp; &nbsp;LastOrderDate = <span style="color: #0000FF;">Last</span><span style="color: #808080;">&#40;</span>OrderDate<span style="color: #808080;">&#41;</span>,</li><li style="" class="li2">&nbsp; &nbsp;SubTotal = <span style="color: #0000FF;">Last</span><span style="color: #808080;">&#40;</span>SubTotal<span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #0000FF;">FROM</span> Orders</li><li style="" class="li2"><span style="color: #0000FF;">GROUP</span> <span style="color: #0000FF;">BY</span> CustomerID</li><li style="" class="li1"><span style="color: #0000FF;">ORDER</span> <span style="color: #0000FF;">BY</span> OrderDate</li></ol></div><div id="cb78599" style="display: none; color: red;"></div></div></div>

<p>What happens in Access is that the Last() aggregate combines with the ORDER BY clause to select values from the row containing the most recent Order Date.</p>

<p>However, these functions are not available in SQL Server, likely because the query engine only does ordering at the very end, after GROUP BY and HAVING are processed. While this may seem like a defect, it is really a deliberate design trade-off, with compensations elsewhere in the engine.</p>

<h2>Test Case</h2>

<p>In order to have enough data to make results significant and also to let others run the same queries against the same data, we are going to use the AdventureWorks sample database.</p>

<p>In our scenario, we want to show customers' account numbers along with the date and subtotal of their most recent order. We're keeping it simple for clarity, but note that you can include as many columns as you like. In a later installment we'll do these same queries with more columns and different scenarios, and will expand on some of the queries a bit. We'll also discuss performance to help you select between them.</p>

<p>Note that the aggregate doesn't have to be on a date. Perhaps you want to know the date of the largest dollar value order per customer. In this case, you'd be doing a Max() on the order value instead of a date, and you would most certainly run into duplicates. Keep this in mind when reading below and when developing your own queries.</p>

<p>The basic query we'll be working with is:</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb28147'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb28147','cb66609'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb28147" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;C.<span style="color: #202020;">AccountNumber</span>,</li><li style="" class="li1">&nbsp; &nbsp;LastOrderDate = <span style="color: #FF00FF;">Max</span><span style="color: #808080;">&#40;</span>O.<span style="color: #202020;">OrderDate</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">FROM</span></li><li style="" class="li1">&nbsp; &nbsp;Sales.<span style="color: #202020;">Customer</span> C</li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">INNER</span> JOIN Sales.<span style="color: #202020;">SalesOrderHeader</span> O <span style="color: #0000FF;">ON</span> C.<span style="color: #202020;">CustomerID</span> = O.<span style="color: #202020;">CustomerID</span></li></ol></div><div id="cb66609" style="display: none; color: red;"></div></div></div>

<p>What we want to do is also return the Subtotal value from the same row as the LastOrderDate.</p>

<h3>Some Approaches to the Problem</h3>

<p>We know of only a few basic approaches to the problem:</p>

<div><p>- <strong>Key Search</strong> -- use the LastOrderDate column as a key (along with customer AccountNumber) to locate the correct rows in the OrderHeader table. This requires an extra join and also the key isn't unique, so we might have to perform another Max() on a unique column and join another time, with the new column added to the key.</p>

<p>- <strong>Number and Filter</strong> -- select all rows from OrderHeader, and number them in a way exploitable to correctly filter out unwanted rows. Observe that this won't require hitting the table again, but it could use a lot of extra resources to temporarily materialize more data. Skipping over obvious poor choices such as a temp table with an ordered update or a cursor, options might be a windowing function (SQL 2005 and up) or a temp table with an identity column (SQL 2000).</p>

<p>- <strong>Simulate MS Access</strong> -- simulate how MS Access works somehow, getting only the data we need in a single table access (seek or scan). Let's imagine how the SQL engine already performs a Max. As it touches each row, it must store the intermediate value that is the best candidate so far for all the seen values. And it has to have one of these per group, per column. All that is needed is that every time it writes the Max() candidate into its temporary storage, it also writes the extra column we want into the same data.</p>

<p>How could we do this ourselves? We need to ORDER BY OrderDate but actually yield SubTotal. SubTotal clearly won't sort in the correct order by itself. Remembering Max(OrderDate->SubTotal), what if it wasn't by itself, and somehow contained the OrderDate, too, to make it sort properly? So here we have an idea about packing both columns into a single value that sorts correctly yet can still be used to get the SubTotal back out. When the engine does its Max() bit as usual on the date and stores the best candidate, it will also be forced to store the other value at the same time (which we can extract later).</p></div>

<p>So let's use those ideas and turn them into real queries. Unless otherwise stated, queries will work with SQL Server 2000.</p>
<p></p>
<h2>Key Search</h2>
<p></p>
<h3>1. Correlated Subquery</h3>

<ul>
  <li>Relies on unique order dates to avoid selecting multiple rows per customer.</li>
  <li>Correlated subqueries perform well with small datasets and badly with large datasets (though better with SQL 2005 and 2008 because they can sometimes get converted to real joins).</li>
  <li>Performance degrades geometrically as rows increase.</li>
  <li>Does not handle NULLs correctly.</li>
</ul>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb54309'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb54309','cb17697'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb54309" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;C.<span style="color: #202020;">AccountNumber</span>,</li><li style="" class="li1">&nbsp; &nbsp;O.<span style="color: #202020;">OrderDate</span>,</li><li style="" class="li2">&nbsp; &nbsp;O.<span style="color: #202020;">SubTotal</span></li><li style="" class="li1"><span style="color: #0000FF;">FROM</span></li><li style="" class="li2">&nbsp; &nbsp;Sales.<span style="color: #202020;">Customer</span> C</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">INNER</span> JOIN Sales.<span style="color: #202020;">SalesOrderHeader</span> O <span style="color: #0000FF;">ON</span> C.<span style="color: #202020;">CustomerID</span> = O.<span style="color: #202020;">CustomerID</span> </li><li style="" class="li2"><span style="color: #0000FF;">WHERE</span></li><li style="" class="li1">&nbsp; &nbsp;O.<span style="color: #202020;">OrderDate</span> = <span style="color: #808080;">&#40;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SELECT</span> <span style="color: #FF00FF;">Max</span><span style="color: #808080;">&#40;</span>OrderDate<span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">FROM</span> SalesOrderHeader O2</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">WHERE</span> O2.<span style="color: #202020;">CustomerID</span> = O.<span style="color: #202020;">CustomerID</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #808080;">&#41;</span></li></ol></div><div id="cb17697" style="display: none; color: red;"></div></div></div>


<p>Another version of correlated subquery which sometimes performs much better is</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb81443'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb81443','cb74944'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb81443" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;C.<span style="color: #202020;">AccountNumber</span>,</li><li style="" class="li1">&nbsp; &nbsp;O.<span style="color: #202020;">OrderDate</span>,</li><li style="" class="li2">&nbsp; &nbsp;O.<span style="color: #202020;">SubTotal</span></li><li style="" class="li1"><span style="color: #0000FF;">FROM</span></li><li style="" class="li2">&nbsp; &nbsp;Sales.<span style="color: #202020;">Customer</span> C</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">INNER</span> JOIN Sales.<span style="color: #202020;">SalesOrderHeader</span> O <span style="color: #0000FF;">ON</span> C.<span style="color: #202020;">CustomerID</span> = O.<span style="color: #202020;">CustomerID</span> </li><li style="" class="li2"><span style="color: #0000FF;">WHERE</span></li><li style="" class="li1">&nbsp; &nbsp;O.<span style="color: #202020;">OrderID</span> = <span style="color: #808080;">&#40;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SELECT</span> <span style="color: #0000FF;">top</span> <span style="color: #000;">1</span> OrderID </li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">FROM</span> SalesOrderHeader O2</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">WHERE</span> O2.<span style="color: #202020;">CustomerID</span> = O.<span style="color: #202020;">CustomerID</span> <span style="color: #0000FF;">order</span> <span style="color: #0000FF;">by</span> O2.<span style="color: #202020;">OrderDate</span> <span style="color: #0000FF;">Desc</span>, O2.<span style="color: #202020;">OrderID</span> <span style="color: #0000FF;">DESC</span><span style="color: #808080;">&#41;</span></li></ol></div><div id="cb74944" style="display: none; color: red;"></div></div></div>

<p>Another variation of this query is (suggested by Alejandro Mesa (Hunchback) in this <a href="http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/0217ddf4-bcab-4f2b-a81c-70841753cb23">MSDN thread</a>):</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb67081'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb67081','cb76799'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb67081" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;C.<span style="color: #202020;">AccountNumber</span>,</li><li style="" class="li1">&nbsp; &nbsp;O1.<span style="color: #202020;">OrderDate</span>,</li><li style="" class="li2">&nbsp; &nbsp;O1.<span style="color: #202020;">SubTotal</span></li><li style="" class="li1"><span style="color: #0000FF;">FROM</span></li><li style="" class="li2">&nbsp; &nbsp;Sales.<span style="color: #202020;">Customer</span> C</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">INNER</span> JOIN Sales.<span style="color: #202020;">SalesOrderHeader</span> O1 <span style="color: #0000FF;">ON</span> C.<span style="color: #202020;">CustomerID</span> = O1.<span style="color: #202020;">CustomerID</span> </li><li style="" class="li2"><span style="color: #0000FF;">WHERE</span> not exists <span style="color: #808080;">&#40;</span><span style="color: #0000FF;">select</span> <span style="color: #000;">1</span> <span style="color: #0000FF;">from</span> Sales.<span style="color: #202020;">SalesOrderHeader</span> O2 <span style="color: #0000FF;">where</span> O2.<span style="color: #202020;">CustomerID</span> = O1.<span style="color: #202020;">CustomerID</span> and O1.<span style="color: #202020;">OrderDate</span> &lt; O2.<span style="color: #202020;">OrderDate</span><span style="color: #808080;">&#41;</span></li></ol></div><div id="cb76799" style="display: none; color: red;"></div></div></div>

<p>Note, that the first variation of this query may return duplicate rows, but the second will always return only one row per group (with the latest OrderID).</p>

<p>The third variation of this query with NOT EXISTS will produce duplicates in case of the same date, but can also be easily adjusted to return only one row with the max OrderID:</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb46085'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb46085','cb59934'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb46085" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;C.<span style="color: #202020;">AccountNumber</span>,</li><li style="" class="li1">&nbsp; &nbsp;O1.<span style="color: #202020;">OrderDate</span>,</li><li style="" class="li2">&nbsp; &nbsp;O1.<span style="color: #202020;">SubTotal</span></li><li style="" class="li1"><span style="color: #0000FF;">FROM</span></li><li style="" class="li2">&nbsp; &nbsp;Sales.<span style="color: #202020;">Customer</span> C</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">INNER</span> JOIN Sales.<span style="color: #202020;">SalesOrderHeader</span> O1 <span style="color: #0000FF;">ON</span> C.<span style="color: #202020;">CustomerID</span> = O1.<span style="color: #202020;">CustomerID</span> </li><li style="" class="li2"><span style="color: #0000FF;">WHERE</span> not exists <span style="color: #808080;">&#40;</span><span style="color: #0000FF;">select</span> <span style="color: #000;">1</span> <span style="color: #0000FF;">from</span> Sales.<span style="color: #202020;">SalesOrderHeader</span> O2 <span style="color: #0000FF;">where</span> O2.<span style="color: #202020;">CustomerID</span> = O1.<span style="color: #202020;">CustomerID</span> and <span style="color: #808080;">&#40;</span>O1.<span style="color: #202020;">OrderDate</span> &lt; O2.<span style="color: #202020;">OrderDate</span> OR </li><li style="" class="li1"><span style="color: #808080;">&#40;</span>O1.<span style="color: #202020;">OrderDate</span> = O2.<span style="color: #202020;">OrderDate</span> and O1.<span style="color: #202020;">OrderID</span> &lt; O2.<span style="color: #202020;">OrderID</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span></li></ol></div><div id="cb59934" style="display: none; color: red;"></div></div></div>

<p></p>
<h3>2. Derived Table</h3>
<p></p>
<ul>
  <li>Relies on unique order dates to avoid selecting multiple rows per customer.</li>
  <li>Performs better than the correlated subquery when querying a significant portion of all customers, but worse when only querying a few, since the last order date for every customer is always calculated.</li>
  <li>Performance degrades linearly as rows increase.</li>
  <li>Does not handle NULLs correctly.</li>
</ul>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb46556'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb46556','cb59401'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb46556" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;C.<span style="color: #202020;">AccountNumber</span>,</li><li style="" class="li1">&nbsp; &nbsp;O.<span style="color: #202020;">OrderDate</span>,</li><li style="" class="li2">&nbsp; &nbsp;O.<span style="color: #202020;">SubTotal</span></li><li style="" class="li1"><span style="color: #0000FF;">FROM</span></li><li style="" class="li2">&nbsp; &nbsp;Sales.<span style="color: #202020;">Customer</span> C</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">INNER</span> JOIN Sales.<span style="color: #202020;">SalesOrderHeader</span> O <span style="color: #0000FF;">ON</span> C.<span style="color: #202020;">CustomerID</span> = O.<span style="color: #202020;">CustomerID</span> </li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">INNER</span> JOIN <span style="color: #808080;">&#40;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SELECT</span> CustomerID, LastOrderDate = <span style="color: #FF00FF;">Max</span><span style="color: #808080;">&#40;</span>OrderDate<span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">FROM</span> Sales.<span style="color: #202020;">SalesOrderHeader</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">GROUP</span> <span style="color: #0000FF;">BY</span> CustomerID</li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #808080;">&#41;</span> O2 <span style="color: #0000FF;">ON</span> O.<span style="color: #202020;">CustomerID</span> = O2.<span style="color: #202020;">CustomerID</span> AND O.<span style="color: #202020;">OrderDate</span> = O2.<span style="color: #202020;">LastOrderDate</span></li></ol></div><div id="cb59401" style="display: none; color: red;"></div></div></div>
<p><br /></p>

<h2>Number and Filter</h2>
<p></p>
<h3>Windowing Functions</h3>

<p>The windowing functions were introduced in SQL Server 2005, so the two queries below will not work in SQL Server 2000.</p>

<ul>
  <li>Will always return one row per customer. Using RANK() instead of ROW_NUMBER() will yield the same results as queries 1 and 2.</li>
  <li>Easily supports not just 1 but <em>n</em> rows per group.</li>
  <li>Performance degrades fairly linearly as rows increase. The windowing functions are fast but huge rowsets can begin to bog them down.</li>
</ul>
<p></p>
<h3>3. Windowing Function - Two Stages</h3>
<p></p>
<ul>
  <li>A common table expression is not needed, but is cleaner. The CTE query can be made into a derived table if desired.</li>
</ul>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb91844'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb91844','cb95147'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb91844" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">WITH</span> OrderData <span style="color: #0000FF;">AS</span> <span style="color: #808080;">&#40;</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">SELECT</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; C.<span style="color: #202020;">AccountNumber</span>,</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; O.<span style="color: #202020;">OrderDate</span>,</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; O.<span style="color: #202020;">SubTotal</span>,</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; Selector = <span style="color: #FF00FF;">ROW_NUMBER</span><span style="color: #808080;">&#40;</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">OVER</span> <span style="color: #808080;">&#40;</span><span style="color: #0000FF;">PARTITION</span> <span style="color: #0000FF;">BY</span> O.<span style="color: #202020;">CustomerID</span> <span style="color: #0000FF;">ORDER</span> <span style="color: #0000FF;">BY</span> O.<span style="color: #202020;">OrderDate</span> <span style="color: #0000FF;">DESC</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">FROM</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; Sales.<span style="color: #202020;">Customer</span> C</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">INNER</span> JOIN Sales.<span style="color: #202020;">SalesOrderHeader</span> O <span style="color: #0000FF;">ON</span> C.<span style="color: #202020;">CustomerID</span> = O.<span style="color: #202020;">CustomerID</span> </li><li style="" class="li2"><span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #0000FF;">SELECT</span> AccountNumber, OrderDate, SubTotal</li><li style="" class="li2"><span style="color: #0000FF;">FROM</span> OrderData</li><li style="" class="li1"><span style="color: #0000FF;">WHERE</span> Selector = <span style="color: #000;">1</span></li></ol></div><div id="cb95147" style="display: none; color: red;"></div></div></div>
<h3>4. Windowing Function - One Stage</h3>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb75673'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb75673','cb74928'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb75673" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span> <span style="color: #0000FF;">TOP</span> <span style="color: #000;">1</span> <span style="color: #0000FF;">WITH</span> TIES</li><li style="" class="li2">&nbsp; &nbsp;C.<span style="color: #202020;">AccountNumber</span>,</li><li style="" class="li1">&nbsp; &nbsp;O.<span style="color: #202020;">OrderDate</span>,</li><li style="" class="li2">&nbsp; &nbsp;O.<span style="color: #202020;">SubTotal</span></li><li style="" class="li1"><span style="color: #0000FF;">FROM</span></li><li style="" class="li2">&nbsp; &nbsp;Sales.<span style="color: #202020;">Customer</span> C</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">INNER</span> JOIN Sales.<span style="color: #202020;">SalesOrderHeader</span> O <span style="color: #0000FF;">ON</span> C.<span style="color: #202020;">CustomerID</span> = O.<span style="color: #202020;">CustomerID</span> </li><li style="" class="li2"><span style="color: #0000FF;">ORDER</span> <span style="color: #0000FF;">BY</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #FF00FF;">ROW_NUMBER</span><span style="color: #808080;">&#40;</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">OVER</span> <span style="color: #808080;">&#40;</span><span style="color: #0000FF;">PARTITION</span> <span style="color: #0000FF;">by</span> O.<span style="color: #202020;">CustomerID</span> <span style="color: #0000FF;">ORDER</span> <span style="color: #0000FF;">BY</span> OrderDate <span style="color: #0000FF;">DESC</span><span style="color: #808080;">&#41;</span></li></ol></div><div id="cb74928" style="display: none; color: red;"></div></div></div>
<p><br /></p>
<p></p>
<h2>Simulate MS Access</h2>
<p></p>
<h3>5. Compound Key, aka Packed Values</h3>

<ul>
  <li>Uses only one table access with a simple GROUP BY.</li>
  <li>Naomi first learned this idea from <a href="http://forum.foxclub.ru/read.php?32,177183,177232#msg-177232">a Russian SQL FAQ</a>.</li>
  <li>Erik cooked up a similar idea in 2008.</li>
  <li>This example uses a varchar column to hold the packed values, but be aware that converting to and from binary is faster than char (plus harder to use and more error-prone) and binary aggregation is faster. The crucial part is being able to faithfully extract the data that was put in.</li>
  <li>This query has no problem with duplicates. It does effectively sort by the full compound value, so if multiple orders for the same customer can be on the same order date and you want some other column to determine which one is selected, it has to be included in the packed data.</li>
  <li>As given, this query does not handle NULLs at all. A few strategic Coalesces can fix that.</li>
  <li>There is no significant performance difference between unpacking one many-item compound value or many one-item compound values (though you'd always include all columns needed for ordering).</li>
</ul>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb40778'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb40778','cb97311'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb40778" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;CustomerID,</li><li style="" class="li1">&nbsp; &nbsp;LastOrderDate,</li><li style="" class="li2">&nbsp; &nbsp;LastSubTotal = <span style="color: #FF00FF;">Convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">money</span>, <span style="color: #FF00FF;">Substring</span><span style="color: #808080;">&#40;</span>DateAndSubtotal, <span style="color: #000;">20</span>, <span style="color: #000;">25</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #0000FF;">FROM</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #808080;">&#40;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CustomerID,</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LastOrderDate = <span style="color: #FF00FF;">Max</span><span style="color: #808080;">&#40;</span>OrderDate<span style="color: #808080;">&#41;</span>,</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;DateAndSubtotal = <span style="color: #FF00FF;">Max</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">50</span><span style="color: #808080;">&#41;</span>, OrderDate, <span style="color: #000;">121</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF00FF;">Convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">50</span><span style="color: #808080;">&#41;</span>, Subtotal<span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">FROM</span> Sales.<span style="color: #202020;">SalesOrderHeader</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">GROUP</span> <span style="color: #0000FF;">BY</span> CustomerID</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #808080;">&#41;</span> X</li></ol></div><div id="cb97311" style="display: none; color: red;"></div></div></div>

<p>Isn't that cool? I don't advocate using it all the time, but when performance is bad and the trade-offs are worth it, do it.</p>

<p>In closing, thank you for visiting. We hope this is useful to you. You might like to see the next installment <a href="http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/including-an-aggregated-column-s-related-2">Including an Aggregated Column's Related Values - Part 2</a>, discussing this issue in further depth.</p>

<p>Erik</p>

<p>P.S. I would like to thank <a href="http://forum.lessthandot.com/memberlist.php?mode=viewprofile&amp;u=314">Naomi</a> for co-authoring this blog post with me. She did the heavy lifting of actually writing queries and testing their performance; I just fleshed out the explanations a bit.</p><div class="item_footer"><p><small><a href="http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/including-an-aggregated-column-s-related">Original post</a> blogged on <a href="http://lessthandot.com/">LessThanDot</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/including-an-aggregated-column-s-related#comments</comments>
			<wfw:commentRss>http://blogs.lessthandot.com/index.php/DataMgmt/?tempskin=_rss2&#38;disp=comments&#38;p=528</wfw:commentRss>
		</item>
				<item>
			<title>Multi-Value Parameters in SSRS</title>
			<link>http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/ssrs_multi_value_parameters</link>
			<pubDate>Fri, 22 May 2009 17:22:45 +0000</pubDate>			<dc:creator>Erik</dc:creator>
			<category domain="main">Data Modelling &amp; Design</category>
<category domain="alt">Microsoft SQL Server</category>			<guid isPermaLink="false">456@http://blogs.lessthandot.com/</guid>
						<description>&lt;h1&gt;Background&lt;/h1&gt;

&lt;p&gt;I have a report that returns specific documentation from the database with one parameter, a CustomerID. The report is bound to a stored procedure which has hard-coded in it the names of the specific documents that should be included. This solution is problematic because when the list of documents needs to change, the SP has to be updated, which means mistakes can be (and have been) made.&lt;/p&gt;

&lt;p&gt;The good step of converting the SP to use a table doesn&#039;t satisfy me fully, because these reports are executed from a special reporting system that also has its own list of document names, so that it knows when to kick off a particular report&amp;#8212;for example, if none of the documents exist, no report will be generated. I didn&#039;t like the idea of depending on having the same data updates made in two places: I should be able to just update the reporting system with the new document names and then trust that the reports will contain the correct data. In the past, we had a mistake where the reporting system received a new document name that didn&#039;t get included in the SP properly, so after finally fixing the SP, I had to do a recovery and resend some reports.&lt;/p&gt;

&lt;p&gt;I realized that what could solve the problem once and for all was to provide the exact list of document names to the SSRS report as a parameter, and have the report pass the document names into the SP, so that even if the SP is not updated (or its source table is not updated), the correct content will still be pulled. The way to do this is with a &quot;multi-value&quot; parameter.&lt;/p&gt;

&lt;h1&gt;Starting Points&lt;/h1&gt;

&lt;p&gt;&amp;#8226; A quick test will show that the way SSRS passes multi-valued parameters to a stored procedure is simply by taking all the values selected and packing them into a comma-delimited string. If any of the items in the list contain a comma, no escaping or special handling is done&amp;#8212;so manual escaping is required.&lt;/p&gt;

&lt;p&gt;&amp;#8226; In case you&#039;re really new to all this, all the report development is being done in Visual Studio 2005, with a project of type Business Intelligence Projects - Report Server Project. I&#039;m sure you can find tutorials elsewhere for how to set up a basic report. Once you have a working report, you&#039;re ready to add a multi-value parameter.&lt;/p&gt;

&lt;p&gt;&amp;#8226; In this article, the multi-value parameter I am working with is a list of document names. So wherever I say document names, you can insert the thing that you are concerned with. If you can guarantee that there will never be a comma in the list, you can skip or edit the parts of my explanation that have special handling for commas.&lt;/p&gt;

&lt;h1&gt;Adding the Multi-Value Parameter&lt;/h1&gt;

&lt;p&gt;What I learned while doing this is probably useful to someone, so here&#039;s a quick rundown of how to modify an SSRS report and a stored procedure to accept and use a multi-valued parameter.&lt;/p&gt;

&lt;h2&gt;Modify the Stored Procedure&lt;/h2&gt;
&lt;ol&gt;&lt;li&gt;&lt;p&gt;Add the new parameter. I copied the old SP to a new name so that I couldn&#039;t possibly mess up the original, and so going forward no one else who works with these things will get confused about which does what.&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb77782&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;CREATE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PROCEDURE&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;MyReport_DocParam&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;@CustomerID &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@DocumentNameParam &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF00FF;&quot;&gt;Max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Please note that any document names with commas must be put inside single quotes.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb89353&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The default value of an empty string allows the SP to be run with just a CustomerID and it will still work. It may not have all the document names, but for testing and development of the SP that may not matter most of the time. I put the comment shown right into the SP to help prevent problems with other people trying to use the SP when I am not around.&lt;/p&gt;

I chose to make the new parameter varchar(Max) because it won&#039;t hurt anything, and on the theory that I don&#039;t like my code breaking, and despite knowing that the list will almost surely never exceed 8000 characters, I&#039;d rather be safe. In SQL 2000 you can probably get by with varchar(8000) or even the text data type.&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;p&gt;Write a value-splitting function.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: I have not experimented with other data types such as Integer. If you have done this and know how it works in SSRS differently from using strings, please post a comment. I suspect that whatever the actual data type of your items, they will have to be passed as a comma-separated string anyway. If your items are fixed-length or easily convert to relatively short fixed-length strings, padding them so the comma delimiters added by SSRS appear at exactly known positions will make your task of splitting much easier. You can just join to a special Numbers table and split at each position. For example, if you can make your inputs always 10 characters long then you can just break the string at every 11th character&amp;#8212;the comma.&lt;/p&gt;

&lt;p&gt;Here&#039;s how I decided to escape commas:&lt;br /&gt;
&amp;#8226; If the value contains a comma, enclose it in single quotes and double up any single quotes in that value.&lt;br /&gt;
&amp;#8226; If the value does not contain a comma, don&#039;t escape it in any way even if it has a single quote.&lt;/p&gt;

&lt;p&gt;I chose this because it is similar to how SQL Server accepts string literals already and should be more familiar to anyone working with my code than other methods (such as backslash-escaping for example). I also considered replacing commas with a character that I know won&#039;t be in the document names such as character 0 or 255 and then restoring it after splitting values apart, but rejected that because it makes it much more difficult to understand and makes it much harder to provide the list of items if the SP is being run from a query window such as Query Analyzer or Management Studio.&lt;/p&gt;

&lt;div style=&quot;border:1px solid black;background-color:#444;color:white;margin:0 20px;padding:0 5px 0 5px;&quot;&gt;&lt;p&gt;&lt;span class=&quot;MT_larger&quot;&gt;&lt;em&gt;&lt;strong&gt;But I Don&#039;t Wanna Escape The Comma&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;&lt;span class=&quot;MT_smaller&quot;&gt;&lt;/p&gt;

&lt;/span&gt;&lt;p&gt;If you don&#039;t think you need to escape commas, please ensure that commas &lt;strong&gt;can&#039;t&lt;/strong&gt; be in your data ever, not that they don&#039;t exist now or &quot;we&#039;ll tell people not to put commas in.&quot; An utterly basic and beginner&#039;s rule of programming is to never trust user input. Bad Things happen when you do. How do you know that in 5 years when you may be gone or on vacation that some new person who never heard about the comma rule won&#039;t enter a comma?&lt;/p&gt;&lt;/div&gt;

&lt;p&gt;Here&#039;s my function to do the unescaping and splitting work:&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb43230&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;CREATE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;FUNCTION&lt;/span&gt; SplitQuotedString &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@String &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF00FF;&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;RETURNS&lt;/span&gt; @&lt;span style=&quot;color: #0000FF;&quot;&gt;Array&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;TABLE&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;Item &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;DECLARE&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @Pos &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @&lt;span style=&quot;color: #0000FF;&quot;&gt;End&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @TextLength &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @Item &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @Fragment &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @InQuotes &lt;span style=&quot;color: #0000FF;&quot;&gt;bit&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @TextLength = &lt;span style=&quot;color: #FF00FF;&quot;&gt;DataLength&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@String&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @TextLength = &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;RETURN&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Pos = &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @InQuotes = &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @String = @String + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;,&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Item = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHILE&lt;/span&gt; &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; = &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @&lt;span style=&quot;color: #0000FF;&quot;&gt;End&lt;/span&gt; = &lt;span style=&quot;color: #FF00FF;&quot;&gt;CharIndex&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;,&#039;&lt;/span&gt;, @String, @Pos&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @&lt;span style=&quot;color: #0000FF;&quot;&gt;End&lt;/span&gt; = &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BREAK&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Fragment = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Substring&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@String, @Pos, @&lt;span style=&quot;color: #0000FF;&quot;&gt;End&lt;/span&gt; - @Pos&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @InQuotes = &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #00AF00;&quot;&gt;--InQuotes becomes false if there are an odd number of single quotes at the end of this fragment&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @InQuotes = &lt;span style=&quot;color: #FF00FF;&quot;&gt;PatIndex&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;%[^&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;]%&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF00FF;&quot;&gt;Reverse&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Fragment&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;x&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; % &lt;span style=&quot;color: #000;&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Item = @Item + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;,&#039;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;Replace&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF00FF;&quot;&gt;Left&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Fragment, &lt;span style=&quot;color: #FF00FF;&quot;&gt;DataLength&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Fragment&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; - &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; + @InQuotes&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;ELSE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @Fragment LIKE &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;%&#039;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @InQuotes = &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Item = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Replace&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF00FF;&quot;&gt;Substring&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Fragment, &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; + @InQuotes, &lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;ELSE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Item = @Fragment&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @InQuotes = &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INSERT&lt;/span&gt; @&lt;span style=&quot;color: #0000FF;&quot;&gt;Array&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;Item&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;VALUES&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Item&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Item = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Pos = @&lt;span style=&quot;color: #0000FF;&quot;&gt;End&lt;/span&gt; + &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;RETURN&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb93798&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You&#039;re welcome to use it, or write your own. You may not agree with how I chose to do it, and if you have any seriously big improvements do let me know. But I was not overly concerned with extracting that last tiny bit of performance, as my strings will never be very long and will never have more than a dozen or so items. I could not use a Numbers table solution since I am doubling up single quotes and in the case of encountering input such as &quot;&#039;&#039;&#039;&#039;&quot; it would incorrectly match an extra time at the second quote mark. Preventing a false match requires knowing if the current quote mark is an even or an odd one, which would need to look backward in the string, which complicated it so much that I just went for a chunk-by-chunk method that looks at each string separated by commas and determines if it begins a quoted string. If so, then each fragment is added to the item until the closing quote mark is encountered, and finally the complete item is added to the output table. If the item is not quoted, it is simply added to the output table.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: In this function I assumed that no individual value would exceed 8000 characters. I also assumed that an item will not be quoted without containing a comma character. If items are quoted that don&#039;t contain commas, this code will break. See the escaping logic I used in the query for the value list producing Dataset on the SSRS report.&lt;/p&gt;

If your data will never have commas in it or you can use the the fixed-length method, then should use your own plain-vanilla split function rather than my unescaping version.&lt;/li&gt;
&lt;p&gt;&lt;/p&gt;&lt;li&gt;&lt;p&gt;Split and use the multi-value string.&lt;/p&gt;

&lt;p&gt;Here&#039;s the code I used, which should be enough of an example to let you develop your own version that suits your needs:&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb75298&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;DECLARE&lt;/span&gt; @DocumentNames &lt;span style=&quot;color: #0000FF;&quot;&gt;TABLE&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; DocumentName &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;60&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; &lt;span style=&quot;color: #FF00FF;&quot;&gt;Coalesce&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@DocumentNameParam, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INSERT&lt;/span&gt; @DocumentNames &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; Item &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;SplitQuotedString&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@DocumentNameParam&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;ELSE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;INSERT&lt;/span&gt; @DocumentNames&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Document Name 1&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Document Name 2&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Document Name 3, Special&#039;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb32461&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To my dismay, I was not allowed to make this SP read from a table. But I am still quite happy because now I don&#039;t care if the SP gets updated with new document names: when the reporting system creates a report, it will pass in document names and always be correct. I have insulated the reporting system against exactly the thing I was trying to avoid: mistakes when updating the SP. I&#039;ll even throw in that I was the one who made the mistake updating the SP last time&amp;#8212;I didn&#039;t know the hard-coded document list was in &lt;strong&gt;three&lt;/strong&gt; places. Now, at least, the list is in one place.&lt;/p&gt;

&lt;p&gt;And finally, using the document names:&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb78122&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;INNER&lt;/span&gt; JOIN @DocumentNames N &lt;span style=&quot;color: #0000FF;&quot;&gt;on&lt;/span&gt; D.&lt;span style=&quot;color: #202020;&quot;&gt;DocumentName&lt;/span&gt; = N.&lt;span style=&quot;color: #202020;&quot;&gt;DocumentName&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb90919&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/li&gt;&lt;br /&gt;
&lt;/ol&gt;&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;Modify The SSRS Report&lt;/h2&gt;
&lt;ol&gt;&lt;li&gt;Update the Dataset. On the Data tab, either create a new Dataset or update an existing Dataset so that it has the correct SP name and finds the new parameter you added. To edit a Dataset, click the &quot;...&quot; button to the right of the Dataset name dropdown.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decide whether the report&#039;s default list of available document names will be hard-coded in the report or supplied by a query. I chose to make it data-driven so that if a new document is added, it will show up in the report without any changes to it, or with only a change to a shared data source, rather than having to change the SSRS report itself. I always prefer to make changes to data or shared objects than to code or types of things that have to be tested and deployed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From query:&lt;/strong&gt; Create a new DataSet that pulls the document names, one per row. Here is the query I used:&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb31775&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;DocNameString =&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;CASE&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;WHEN&lt;/span&gt; DocName LIKE &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;%,%&#039;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;THEN&lt;/span&gt; &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;Replace&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;DocName, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;ELSE&lt;/span&gt; DocName&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;DocName&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; ReportDocName&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHERE&lt;/span&gt; ReportID = &lt;span style=&quot;color: #000;&quot;&gt;62&lt;/span&gt; &lt;span style=&quot;color: #00AF00;&quot;&gt;-- my particular report that has multiple document names&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;ORDER&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; DocName&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb78941&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is the logic that I wrote the SplitQuotedString to match. If you change how you escape commas, you&#039;ll need to write your own splitting/unescaping function. Run the query to make sure it&#039;s working correctly. It should have two columns, one with commas escaped, and one with them unescaped. If you don&#039;t have to escape commas in your data, then one column is okay. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-queried:&lt;/strong&gt; Run a query manually to extract the list you want or locate the values wherever they are. Keep this handy to paste in later.&lt;/li&gt;&lt;/p&gt;
&lt;li&gt;&lt;p&gt;Select Report-&gt;Report Parameters. If there isn&#039;t already a new parameter automatically added by the fact that your SP now has a new parameter, then Add a new parameter.&lt;br /&gt;
&amp;#8226; Name: Give it the same name that you called the parameter in your SP. For me: DocumentNameParam.&lt;br /&gt;
&amp;#8226; Data type: String&lt;br /&gt;
&amp;#8226; Prompt: Document Names&lt;br /&gt;
&amp;#8226; Check the &quot;Multi-value&quot; checkbox. I also checked &quot;Allow blank value&quot; because if no names are specified, I want the SP&#039;s list of document names to take over. You cannot choose &quot;Allow null value&quot; with a Multi-value parameter (at least, I couldn&#039;t select it and I think that is the reason).&lt;br /&gt;
&amp;#8226; Available values:&lt;br /&gt;
- For &quot;Non-queried&quot; paste in each option, one at a time, from the list of options you built earlier.&lt;br /&gt;
- For &quot;From query&quot; choose the Dataset you created that displays the possible list. For &quot;Value field&quot; select the column that has commas escaped, and for &quot;Label field&quot; select the one that is plain. If your Dataset only has one column, use it in both places.&lt;br /&gt;
&amp;#8226; Default values:&lt;br /&gt;
- For &quot;Non-queried&quot; paste in each option that you want to be selected by default.&lt;br /&gt;
- For &quot;From query&quot; choose your list Dataset, or perhaps select a special default Dataset you created that is different from the list of all possible options. I used the same Dataset since I want all values to be selected by default.&lt;/p&gt;
&lt;p class=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;http://blogs.lessthandot.com/media/blogs/DataMgmt/ssrs_multi_value_parameters/MultiValueReportParameters.PNG&quot; alt=&quot;SSRS Report Parameters&quot; title=&quot;Creating a Multi-value Parameter&quot; /&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you had to add the multi-value report parameter manually, edit the source Dataset and make sure it is mapped properly. Click on the Data tab, select the correct Dataset, click the &quot;...&quot; edit button, select Parameters, and make sure that the Name is mapped to the Value.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://blogs.lessthandot.com/media/blogs/DataMgmt/ssrs_multi_value_parameters/MultiValueDataSet.PNG&quot; alt=&quot;SSRS Dataset Parameters&quot; title=&quot;Mapping A Dataset Parameter to a Report Parameter&quot; /&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;/p&gt;

&lt;h1&gt;Happily Use Your Shiny New Report&lt;/h1&gt;

&lt;p&gt;I hope that this article has been useful to you, and helps you get a Multi-value parameter added to your SSRS report in no time!&lt;/p&gt;

&lt;p&gt;Erik&lt;br /&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;span class=&quot;MT_smaller&quot;&gt;&lt;strong&gt;Afterthoughts&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#8226; You &lt;em&gt;could&lt;/em&gt; use a query instead of a stored procedure.&lt;br /&gt;
&amp;#8226; Think carefully before using a multi-valued parameter to solve problems that should be solved by database normalization. A multi-value column in a database is a BAD idea if you ever have to work with the individual items. Don&#039;t try to adapt this solution to such a column. Fix the database design instead.&lt;/span&gt;&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/ssrs_multi_value_parameters&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://lessthandot.com/&quot;&gt;LessThanDot&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<h1>Background</h1>

<p>I have a report that returns specific documentation from the database with one parameter, a CustomerID. The report is bound to a stored procedure which has hard-coded in it the names of the specific documents that should be included. This solution is problematic because when the list of documents needs to change, the SP has to be updated, which means mistakes can be (and have been) made.</p>

<p>The good step of converting the SP to use a table doesn't satisfy me fully, because these reports are executed from a special reporting system that also has its own list of document names, so that it knows when to kick off a particular report&#8212;for example, if none of the documents exist, no report will be generated. I didn't like the idea of depending on having the same data updates made in two places: I should be able to just update the reporting system with the new document names and then trust that the reports will contain the correct data. In the past, we had a mistake where the reporting system received a new document name that didn't get included in the SP properly, so after finally fixing the SP, I had to do a recovery and resend some reports.</p>

<p>I realized that what could solve the problem once and for all was to provide the exact list of document names to the SSRS report as a parameter, and have the report pass the document names into the SP, so that even if the SP is not updated (or its source table is not updated), the correct content will still be pulled. The way to do this is with a "multi-value" parameter.</p>

<h1>Starting Points</h1>

<p>&#8226; A quick test will show that the way SSRS passes multi-valued parameters to a stored procedure is simply by taking all the values selected and packing them into a comma-delimited string. If any of the items in the list contain a comma, no escaping or special handling is done&#8212;so manual escaping is required.</p>

<p>&#8226; In case you're really new to all this, all the report development is being done in Visual Studio 2005, with a project of type Business Intelligence Projects - Report Server Project. I'm sure you can find tutorials elsewhere for how to set up a basic report. Once you have a working report, you're ready to add a multi-value parameter.</p>

<p>&#8226; In this article, the multi-value parameter I am working with is a list of document names. So wherever I say document names, you can insert the thing that you are concerned with. If you can guarantee that there will never be a comma in the list, you can skip or edit the parts of my explanation that have special handling for commas.</p>

<h1>Adding the Multi-Value Parameter</h1>

<p>What I learned while doing this is probably useful to someone, so here's a quick rundown of how to modify an SSRS report and a stored procedure to accept and use a multi-valued parameter.</p>

<h2>Modify the Stored Procedure</h2>
<ol><li><p>Add the new parameter. I copied the old SP to a new name so that I couldn't possibly mess up the original, and so going forward no one else who works with these things will get confused about which does what.</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb67589'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb67589','cb43491'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb67589" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">PROCEDURE</span> dbo.<span style="color: #202020;">MyReport_DocParam</span></li><li style="" class="li2">&nbsp; &nbsp;@CustomerID <span style="color: #0000FF;">int</span>,</li><li style="" class="li1">&nbsp; &nbsp;@DocumentNameParam <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">Max</span><span style="color: #808080;">&#41;</span> = <span style="color: #FF0000;">''</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #00AF00;">-- Please note that any document names with commas must be put inside single quotes.</span></li></ol></div><div id="cb43491" style="display: none; color: red;"></div></div></div>
<p>The default value of an empty string allows the SP to be run with just a CustomerID and it will still work. It may not have all the document names, but for testing and development of the SP that may not matter most of the time. I put the comment shown right into the SP to help prevent problems with other people trying to use the SP when I am not around.</p>

I chose to make the new parameter varchar(Max) because it won't hurt anything, and on the theory that I don't like my code breaking, and despite knowing that the list will almost surely never exceed 8000 characters, I'd rather be safe. In SQL 2000 you can probably get by with varchar(8000) or even the text data type.</li>
<p></p><li><p>Write a value-splitting function.</p>

<p><em>Note</em>: I have not experimented with other data types such as Integer. If you have done this and know how it works in SSRS differently from using strings, please post a comment. I suspect that whatever the actual data type of your items, they will have to be passed as a comma-separated string anyway. If your items are fixed-length or easily convert to relatively short fixed-length strings, padding them so the comma delimiters added by SSRS appear at exactly known positions will make your task of splitting much easier. You can just join to a special Numbers table and split at each position. For example, if you can make your inputs always 10 characters long then you can just break the string at every 11th character&#8212;the comma.</p>

<p>Here's how I decided to escape commas:<br />
&#8226; If the value contains a comma, enclose it in single quotes and double up any single quotes in that value.<br />
&#8226; If the value does not contain a comma, don't escape it in any way even if it has a single quote.</p>

<p>I chose this because it is similar to how SQL Server accepts string literals already and should be more familiar to anyone working with my code than other methods (such as backslash-escaping for example). I also considered replacing commas with a character that I know won't be in the document names such as character 0 or 255 and then restoring it after splitting values apart, but rejected that because it makes it much more difficult to understand and makes it much harder to provide the list of items if the SP is being run from a query window such as Query Analyzer or Management Studio.</p>

<div style="border:1px solid black;background-color:#444;color:white;margin:0 20px;padding:0 5px 0 5px;"><p><span class="MT_larger"><em><strong>But I Don't Wanna Escape The Comma</strong></em></span><span class="MT_smaller"></p>

</span><p>If you don't think you need to escape commas, please ensure that commas <strong>can't</strong> be in your data ever, not that they don't exist now or "we'll tell people not to put commas in." An utterly basic and beginner's rule of programming is to never trust user input. Bad Things happen when you do. How do you know that in 5 years when you may be gone or on vacation that some new person who never heard about the comma rule won't enter a comma?</p></div>

<p>Here's my function to do the unescaping and splitting work:</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb20822'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb20822','cb69655'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb20822" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">FUNCTION</span> SplitQuotedString <span style="color: #808080;">&#40;</span>@String <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">max</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">RETURNS</span> @<span style="color: #0000FF;">Array</span> <span style="color: #0000FF;">TABLE</span> <span style="color: #808080;">&#40;</span>Item <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #0000FF;">AS</span></li><li style="" class="li2"><span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">DECLARE</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; @Pos <span style="color: #0000FF;">int</span>,</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; @<span style="color: #0000FF;">End</span> <span style="color: #0000FF;">int</span>,</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; @TextLength <span style="color: #0000FF;">int</span>,</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; @Item <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; @Fragment <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; @InQuotes <span style="color: #0000FF;">bit</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @TextLength = <span style="color: #FF00FF;">DataLength</span><span style="color: #808080;">&#40;</span>@String<span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">IF</span> @TextLength = <span style="color: #000;">0</span> <span style="color: #0000FF;">RETURN</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @Pos = <span style="color: #000;">1</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @InQuotes = <span style="color: #000;">0</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @String = @String + <span style="color: #FF0000;">','</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @Item = <span style="color: #FF0000;">''</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">WHILE</span> <span style="color: #000;">1</span> = <span style="color: #000;">1</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @<span style="color: #0000FF;">End</span> = <span style="color: #FF00FF;">CharIndex</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">','</span>, @String, @Pos<span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">IF</span> @<span style="color: #0000FF;">End</span> = <span style="color: #000;">0</span> <span style="color: #0000FF;">BREAK</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @Fragment = <span style="color: #FF00FF;">Substring</span><span style="color: #808080;">&#40;</span>@String, @Pos, @<span style="color: #0000FF;">End</span> - @Pos<span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">IF</span> @InQuotes = <span style="color: #000;">1</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #00AF00;">--InQuotes becomes false if there are an odd number of single quotes at the end of this fragment</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @InQuotes = <span style="color: #FF00FF;">PatIndex</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'%[^'</span><span style="color: #FF0000;">']%'</span>, <span style="color: #FF00FF;">Reverse</span><span style="color: #808080;">&#40;</span>@Fragment<span style="color: #808080;">&#41;</span> + <span style="color: #FF0000;">'x'</span><span style="color: #808080;">&#41;</span> % <span style="color: #000;">2</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @Item = @Item + <span style="color: #FF0000;">','</span> + <span style="color: #FF00FF;">Replace</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">Left</span><span style="color: #808080;">&#40;</span>@Fragment, <span style="color: #FF00FF;">DataLength</span><span style="color: #808080;">&#40;</span>@Fragment<span style="color: #808080;">&#41;</span> - <span style="color: #000;">1</span> + @InQuotes<span style="color: #808080;">&#41;</span>, <span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span>, <span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">END</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">ELSE</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000FF;">IF</span> @Fragment LIKE <span style="color: #FF0000;">''</span><span style="color: #FF0000;">'%'</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @InQuotes = <span style="color: #000;">1</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @Item = <span style="color: #FF00FF;">Replace</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">Substring</span><span style="color: #808080;">&#40;</span>@Fragment, <span style="color: #000;">1</span> + @InQuotes, <span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>, <span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span>, <span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000FF;">END</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000FF;">ELSE</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @Item = @Fragment</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000FF;">END</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">END</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">IF</span> @InQuotes = <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000FF;">INSERT</span> @<span style="color: #0000FF;">Array</span> <span style="color: #808080;">&#40;</span>Item<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">VALUES</span> <span style="color: #808080;">&#40;</span>@Item<span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @Item = <span style="color: #FF0000;">''</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">END</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @Pos = @<span style="color: #0000FF;">End</span> + <span style="color: #000;">1</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">END</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">RETURN</span></li><li style="" class="li2"><span style="color: #0000FF;">END</span></li></ol></div><div id="cb69655" style="display: none; color: red;"></div></div></div>
<p>You're welcome to use it, or write your own. You may not agree with how I chose to do it, and if you have any seriously big improvements do let me know. But I was not overly concerned with extracting that last tiny bit of performance, as my strings will never be very long and will never have more than a dozen or so items. I could not use a Numbers table solution since I am doubling up single quotes and in the case of encountering input such as "''''" it would incorrectly match an extra time at the second quote mark. Preventing a false match requires knowing if the current quote mark is an even or an odd one, which would need to look backward in the string, which complicated it so much that I just went for a chunk-by-chunk method that looks at each string separated by commas and determines if it begins a quoted string. If so, then each fragment is added to the item until the closing quote mark is encountered, and finally the complete item is added to the output table. If the item is not quoted, it is simply added to the output table.</p>

<p><em>Note</em>: In this function I assumed that no individual value would exceed 8000 characters. I also assumed that an item will not be quoted without containing a comma character. If items are quoted that don't contain commas, this code will break. See the escaping logic I used in the query for the value list producing Dataset on the SSRS report.</p>

If your data will never have commas in it or you can use the the fixed-length method, then should use your own plain-vanilla split function rather than my unescaping version.</li>
<p></p><li><p>Split and use the multi-value string.</p>

<p>Here's the code I used, which should be enough of an example to let you develop your own version that suits your needs:</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb91595'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb91595','cb63898'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb91595" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">DECLARE</span> @DocumentNames <span style="color: #0000FF;">TABLE</span> <span style="color: #808080;">&#40;</span></li><li style="" class="li2">&nbsp; &nbsp; DocumentName <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">60</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">IF</span> <span style="color: #FF00FF;">Coalesce</span><span style="color: #808080;">&#40;</span>@DocumentNameParam, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span> = <span style="color: #FF0000;">''</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">INSERT</span> @DocumentNames <span style="color: #0000FF;">SELECT</span> Item <span style="color: #0000FF;">FROM</span> dbo.<span style="color: #202020;">SplitQuotedString</span><span style="color: #808080;">&#40;</span>@DocumentNameParam<span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">END</span></li><li style="" class="li1"><span style="color: #0000FF;">ELSE</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">INSERT</span> @DocumentNames</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">SELECT</span> <span style="color: #FF0000;">'Document Name 1'</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> <span style="color: #FF0000;">'Document Name 2'</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> <span style="color: #FF0000;">'Document Name 3, Special'</span></li><li style="" class="li2"><span style="color: #0000FF;">END</span></li></ol></div><div id="cb63898" style="display: none; color: red;"></div></div></div>
<p>To my dismay, I was not allowed to make this SP read from a table. But I am still quite happy because now I don't care if the SP gets updated with new document names: when the reporting system creates a report, it will pass in document names and always be correct. I have insulated the reporting system against exactly the thing I was trying to avoid: mistakes when updating the SP. I'll even throw in that I was the one who made the mistake updating the SP last time&#8212;I didn't know the hard-coded document list was in <strong>three</strong> places. Now, at least, the list is in one place.</p>

<p>And finally, using the document names:</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb6955'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb6955','cb36488'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb6955" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">INNER</span> JOIN @DocumentNames N <span style="color: #0000FF;">on</span> D.<span style="color: #202020;">DocumentName</span> = N.<span style="color: #202020;">DocumentName</span></li></ol></div><div id="cb36488" style="display: none; color: red;"></div></div></div></li><br />
</ol><p></p>

<h2>Modify The SSRS Report</h2>
<ol><li>Update the Dataset. On the Data tab, either create a new Dataset or update an existing Dataset so that it has the correct SP name and finds the new parameter you added. To edit a Dataset, click the "..." button to the right of the Dataset name dropdown.</li>
<li><p>Decide whether the report's default list of available document names will be hard-coded in the report or supplied by a query. I chose to make it data-driven so that if a new document is added, it will show up in the report without any changes to it, or with only a change to a shared data source, rather than having to change the SSRS report itself. I always prefer to make changes to data or shared objects than to code or types of things that have to be tested and deployed.</p>

<p><strong>From query:</strong> Create a new DataSet that pulls the document names, one per row. Here is the query I used:</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb85922'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb85922','cb21048'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb85922" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span></li><li style="" class="li2">&nbsp; &nbsp;DocNameString =</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">CASE</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">WHEN</span> DocName LIKE <span style="color: #FF0000;">'%,%'</span> <span style="color: #0000FF;">THEN</span> <span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span> + <span style="color: #FF00FF;">Replace</span><span style="color: #808080;">&#40;</span>DocName, <span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span>, <span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF0000;">''</span><span style="color: #FF0000;">''</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">ELSE</span> DocName</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">END</span>,</li><li style="" class="li1">&nbsp; &nbsp;DocName</li><li style="" class="li2"><span style="color: #0000FF;">FROM</span> ReportDocName</li><li style="" class="li1"><span style="color: #0000FF;">WHERE</span> ReportID = <span style="color: #000;">62</span> <span style="color: #00AF00;">-- my particular report that has multiple document names</span></li><li style="" class="li2"><span style="color: #0000FF;">ORDER</span> <span style="color: #0000FF;">BY</span> DocName</li></ol></div><div id="cb21048" style="display: none; color: red;"></div></div></div>
<p>This is the logic that I wrote the SplitQuotedString to match. If you change how you escape commas, you'll need to write your own splitting/unescaping function. Run the query to make sure it's working correctly. It should have two columns, one with commas escaped, and one with them unescaped. If you don't have to escape commas in your data, then one column is okay. </p>

<p><strong>Non-queried:</strong> Run a query manually to extract the list you want or locate the values wherever they are. Keep this handy to paste in later.</li></p>
<li><p>Select Report->Report Parameters. If there isn't already a new parameter automatically added by the fact that your SP now has a new parameter, then Add a new parameter.<br />
&#8226; Name: Give it the same name that you called the parameter in your SP. For me: DocumentNameParam.<br />
&#8226; Data type: String<br />
&#8226; Prompt: Document Names<br />
&#8226; Check the "Multi-value" checkbox. I also checked "Allow blank value" because if no names are specified, I want the SP's list of document names to take over. You cannot choose "Allow null value" with a Multi-value parameter (at least, I couldn't select it and I think that is the reason).<br />
&#8226; Available values:<br />
- For "Non-queried" paste in each option, one at a time, from the list of options you built earlier.<br />
- For "From query" choose the Dataset you created that displays the possible list. For "Value field" select the column that has commas escaped, and for "Label field" select the one that is plain. If your Dataset only has one column, use it in both places.<br />
&#8226; Default values:<br />
- For "Non-queried" paste in each option that you want to be selected by default.<br />
- For "From query" choose your list Dataset, or perhaps select a special default Dataset you created that is different from the list of all possible options. I used the same Dataset since I want all values to be selected by default.</p>
<p class="text-align:center;"><img src="http://blogs.lessthandot.com/media/blogs/DataMgmt/ssrs_multi_value_parameters/MultiValueReportParameters.PNG" alt="SSRS Report Parameters" title="Creating a Multi-value Parameter" /></p></li>
<li><p>If you had to add the multi-value report parameter manually, edit the source Dataset and make sure it is mapped properly. Click on the Data tab, select the correct Dataset, click the "..." edit button, select Parameters, and make sure that the Name is mapped to the Value.</p>

<p><img src="http://blogs.lessthandot.com/media/blogs/DataMgmt/ssrs_multi_value_parameters/MultiValueDataSet.PNG" alt="SSRS Dataset Parameters" title="Mapping A Dataset Parameter to a Report Parameter" /></p></li></ol><p></p>

<h1>Happily Use Your Shiny New Report</h1>

<p>I hope that this article has been useful to you, and helps you get a Multi-value parameter added to your SSRS report in no time!</p>

<p>Erik<br />
<br /><br />
<span class="MT_smaller"><strong>Afterthoughts</strong><br />
<br />
&#8226; You <em>could</em> use a query instead of a stored procedure.<br />
&#8226; Think carefully before using a multi-valued parameter to solve problems that should be solved by database normalization. A multi-value column in a database is a BAD idea if you ever have to work with the individual items. Don't try to adapt this solution to such a column. Fix the database design instead.</span></p><div class="item_footer"><p><small><a href="http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/ssrs_multi_value_parameters">Original post</a> blogged on <a href="http://lessthandot.com/">LessThanDot</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/ssrs_multi_value_parameters#comments</comments>
			<wfw:commentRss>http://blogs.lessthandot.com/index.php/DataMgmt/?tempskin=_rss2&#38;disp=comments&#38;p=456</wfw:commentRss>
		</item>
				<item>
			<title>SQL Server: When 8000 Characters Is Not Enough</title>
			<link>http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/sql-2000-when-8000-characters-is-not-eno</link>
			<pubDate>Mon, 06 Apr 2009 21:24:51 +0000</pubDate>			<dc:creator>Erik</dc:creator>
			<category domain="main">Microsoft SQL Server</category>			<guid isPermaLink="false">386@http://blogs.lessthandot.com/</guid>
						<description>&lt;p&gt;MS SQL Server 2000 has a limitation of 8000 characters in a varchar variable. The historical reason for this limitation, I believe, is related to the 8k size of data pages, where in-row data can&#039;t exceed something like 8060 bytes (actual numbers vary a little).&lt;/p&gt;

&lt;p&gt;But what if you need to work with data that is longer than 8000 characters? When storing data in a table, you can use the text datatype which is stored out-of-row (though there are options about storing strings shorter than 8k characters in-row and then moving them out-of-row if they grow). But you can&#039;t use the text datatype as a variable. Look:&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb90300&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;DECLARE&lt;/span&gt; @longdata &lt;span style=&quot;color: #0000FF;&quot;&gt;text&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb33164&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;span class=&quot;MT_red&quot;&gt;Msg 2739, Level 16, State 1, Line 1&lt;br /&gt;
The text, ntext, and image data types are invalid for local variables.&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;But while that seems definitive, it is not the whole story, because you &lt;strong&gt;can &lt;/strong&gt;use the text data type as a parameter in a stored procedure:&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb65566&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;CREATE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PROCEDURE&lt;/span&gt; DisplayText @longdata &lt;span style=&quot;color: #0000FF;&quot;&gt;text&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; @longdata&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb35562&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This works fine, but there are limitations on what can be done with that @longdata variable just like there are with text columns, such as the inability to use the Len() function (use DataLength instead).&lt;/p&gt;

&lt;p&gt;If you truly must have variables with more than 8000 characters in a stored procedure, but they can&#039;t be passed in as parameters, then you are now in the unfortunate position of having to use tables and text pointers. You&#039;ll need the functions TEXTPTR, WRITETEXT, UPDATETEXT, and READTEXT. With these, you can work with pieces of the long data types (no longer than 8000 characters at a time in a variable).&lt;/p&gt;

&lt;p&gt;Here&#039;s an example of putting more than 8000 characters into a column in an SP:&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb7236&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;CREATE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;TABLE&lt;/span&gt; #Table &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;id &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;identity&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;,&lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;primary&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;key&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;clustered&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;longdata &lt;span style=&quot;color: #0000FF;&quot;&gt;text&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;INSERT&lt;/span&gt; #Table &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;longdata&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;VALUES&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;data to be added to-&amp;gt;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;INSERT&lt;/span&gt; #Table &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;longdata&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;VALUES&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;more data-&amp;gt;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;DECLARE&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;@id &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@chunknum &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@ptr &lt;span style=&quot;color: #0000FF;&quot;&gt;varbinary&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;16&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@textchunk &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @id = &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHILE&lt;/span&gt; &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; = &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;TOP&lt;/span&gt; &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt; @id = id, @ptr = &lt;span style=&quot;color: #FF00FF;&quot;&gt;TextPtr&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;longdata&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; #Table &lt;span style=&quot;color: #0000FF;&quot;&gt;WHERE&lt;/span&gt; id &amp;gt; @id &lt;span style=&quot;color: #0000FF;&quot;&gt;ORDER&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BY&lt;/span&gt; id&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; &lt;span style=&quot;color: #FF00FF;&quot;&gt;@@RowCount&lt;/span&gt; = &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BREAK&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @chunknum = &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHILE&lt;/span&gt; @chunknum &amp;lt;= &lt;span style=&quot;color: #000;&quot;&gt;5&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @textchunk = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Replicate&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;Char&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;96&lt;/span&gt; + @chunknum&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UPDATETEXT&lt;/span&gt; #Table.&lt;span style=&quot;color: #202020;&quot;&gt;longdata&lt;/span&gt; @ptr NULL NULL @textchunk&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @chunknum = @chunknum + &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; * &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; #Table&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;DROP&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;TABLE&lt;/span&gt; #Table&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb11317&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can see that you have to loop over each row, and then loop over each chunk of data you want to read from or write to the column.&lt;/p&gt;

&lt;p&gt;Now you know the basics of handling more than 8000 characters in SQL 2000. But there are a few subtle things you should know:&lt;/p&gt;

&lt;p&gt;&amp;#8226; The 8000-character limitation does not apply to literal strings, just variables and rowsets. This means that with the DisplayText stored procedure above you can put in more than 8000 characters like so:&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb68936&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; DisplayText &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&amp;lt;more than 8000 characters here&amp;gt;&#039;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb86954&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This does not mean you can somehow exceed 8000 characters with a commonly-tried but mistaken method such as&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb70196&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #FF00FF;&quot;&gt;Left&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;longdata, &lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;Substring&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;longdata, &lt;span style=&quot;color: #000;&quot;&gt;8001&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;Substring&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;longdata, &lt;span style=&quot;color: #000;&quot;&gt;16001&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb45718&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Sure, this may actually temporarily create a longer string (I don&#039;t know for sure) but the final value in the rowset will not exceed 8000 characters.&lt;/p&gt;

&lt;p&gt;You can concatenate strings when submitting dynamic SQL statements:&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb31161&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;DECLARE&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;@SQL1 &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@SQL2 &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@SQL3 &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@SQL4 &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @SQl1 = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;8000 characters here&#039;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @SQl2 = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;8000 characters here&#039;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @SQl3 = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;8000 characters here&#039;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @SQl4 = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;8000 characters here&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@SQL1 + @SQL2 + @SQL3 + @SQL4&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb52404&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;While I can&#039;t really recommend this method, if you are desperate and this is the only way to get the job done, it&#039;s a possibility. I&#039;ve personally only used it in two narrow situations: creating pre-processed SQL objects where the dynamic SQL is executed rarely only when something changes, and the code it creates is static until the next change. One creates history-keeping triggers, and the other builds a standard set of pivoted views in response to changes of the metadata definitions of some web objects. Both required this method to be able to handle the number of columns possible. &lt;/p&gt;

&lt;p&gt;&amp;#8226; SQL 2005 has a new &#039;max&#039; keyword for the length of the (n)var/char data types that allows variables to be as big as the (n)text datatype can be. You can do anything to them that you could with regular varchar types, but behind the scenes they function like the text data type with values less than 8000 characters in-row and values greater than 8000 characters stored in out-of-row pages.&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb30153&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;DECLARE&lt;/span&gt; @longdata &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF00FF;&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @longdata = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&amp;lt;more than 8000 characters here&amp;gt;&#039;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb64223&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Max here simply means that the data type can go up to the maximum storage size allowed, which is 2^31-1 bytes (minus 2 more bytes for presumably a length value). Note that you can&#039;t specify varchar(16000) or some value over 8000. You only get between 1 and 8000, or the special identifier &lt;em&gt;max&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As a practical example of using a text datatype to defeat the 8000-character limitation in MS SQL Server 2000, here is a SendMail stored procedure that will use the CDO.Message object to send email with a body longer than 8000 characters. Note: put in your mail server name or make it a parameter or perhaps make it read from a table!&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb12710&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;CREATE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PROCEDURE&lt;/span&gt; SendMail&lt;br /&gt;&amp;nbsp; &amp;nbsp;@&lt;span style=&quot;color: #0000FF;&quot;&gt;From&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@&lt;span style=&quot;color: #0000FF;&quot;&gt;To&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@Subject &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;No Subject&#039;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@TextBody &lt;span style=&quot;color: #0000FF;&quot;&gt;text&lt;/span&gt; = NULL,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@HtmlBody &lt;span style=&quot;color: #0000FF;&quot;&gt;text&lt;/span&gt; = NULL&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Written by Erik E&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Sends an email using the CDO.Message object and the SP_OA procedures.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Notably, accepts text input for emails longer than 8000 characters.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;DECLARE&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;@CDOMessage &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@ReturnCode &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OACREATE&lt;/span&gt; &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, @CDOMessage &lt;span style=&quot;color: #0000FF;&quot;&gt;OUT&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, NULL, NULL&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OASETPROPERTY&lt;/span&gt; @CDOMessage, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;From&#039;&lt;/span&gt;, @&lt;span style=&quot;color: #0000FF;&quot;&gt;From&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;From&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, @&lt;span style=&quot;color: #0000FF;&quot;&gt;From&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OASETPROPERTY&lt;/span&gt; @CDOMessage, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;To&#039;&lt;/span&gt;, @&lt;span style=&quot;color: #0000FF;&quot;&gt;To&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;To&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, @&lt;span style=&quot;color: #0000FF;&quot;&gt;To&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OASETPROPERTY&lt;/span&gt; @CDOMessage, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Subject&#039;&lt;/span&gt;, @Subject&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Subject&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, @Subject&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @TextBody &lt;span style=&quot;color: #0000FF;&quot;&gt;IS&lt;/span&gt; NOT NULL &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OASETPROPERTY&lt;/span&gt; @CDOMessage, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;TextBody&#039;&lt;/span&gt;, @TextBody&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;TextBody&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF00FF;&quot;&gt;Convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, @TextBody&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @HtmlBody &lt;span style=&quot;color: #0000FF;&quot;&gt;IS&lt;/span&gt; NOT NULL &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OASETPROPERTY&lt;/span&gt; @CDOMessage, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;HtmlBody&#039;&lt;/span&gt;, @HtmlBody&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;HtmlBody&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF00FF;&quot;&gt;Convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, @HtmlBody&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OASETPROPERTY&lt;/span&gt; @CDOMessage, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Configuration.Fields(&amp;quot;http://schemas.microsoft.com/cdo/configuration/sendusing&amp;quot;).Value&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;2&#039;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Configuration.Fields(&amp;quot;http://schemas.microsoft.com/cdo/configuration/sendusing&amp;quot;).Value&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;2&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OASETPROPERTY&lt;/span&gt; @CDOMessage, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Configuration.Fields(&amp;quot;http://schemas.microsoft.com/cdo/configuration/smtpserver&amp;quot;).Value&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;YourMailServerName&#039;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Configuration.Fields(&amp;quot;http://schemas.microsoft.com/cdo/configuration/smtpserver&amp;quot;).Value&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;YourMailServerName&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OASETPROPERTY&lt;/span&gt; @CDOMessage, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Configuration.Fields(&amp;quot;http://schemas.microsoft.com/cdo/configuration/smtpserverport&amp;quot;).Value&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;25&#039;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Configuration.Fields(&amp;quot;http://schemas.microsoft.com/cdo/configuration/smtpserverport&amp;quot;).Value&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;25&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OAMETHOD&lt;/span&gt; @CDOMessage, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Configuration.Fields.Update&#039;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Configuration.Fields.Update&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, NULL&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OAMETHOD&lt;/span&gt; @CDOMessage, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Send&#039;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Send&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, NULL&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;GOTO&lt;/span&gt; Err &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;Err:&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @CDOMessage &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; @ReturnCode = &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_OADESTROY&lt;/span&gt; @CDOMessage&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;IF&lt;/span&gt; @ReturnCode &amp;lt;&amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;PRINT&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;ObjectErrorFunc&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@CDOMessage, @ReturnCode, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;CDO.Message&#039;&lt;/span&gt;, NULL, NULL&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb4618&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The error handling here after each SP_OA SP call uses a custom function I wrote. I found it to be invaluable when debugging problems with OLE calls to various objects from SQL Server. You may either tear out this error handling, call the sp_OAGetErrorInfo procedure yourself, or use mine, which is below (plus a couple of dependent functions that you may want to rewrite/modify/reimplement/stop using).&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb60556&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;CREATE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;FUNCTION&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#91;&lt;/span&gt;dbo&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#93;&lt;/span&gt;.&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#91;&lt;/span&gt;ObjectErrorFunc&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#93;&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;@&lt;span style=&quot;color: #0000FF;&quot;&gt;Object&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@ReturnCode &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;@Context &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #00AF00;&quot;&gt;-- Property or Method&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;@ObjectType &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #00AF00;&quot;&gt;-- Object Name, when known&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;@&lt;span style=&quot;color: #0000FF;&quot;&gt;Value&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;sql_variant&lt;/span&gt; &lt;span style=&quot;color: #00AF00;&quot;&gt;-- Parameter value, if known&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;RETURNS&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Written by Erik E&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Makes (more) sense out of error codes when using the OLE sp_OA procedures.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Sometimes the message returned by sp_OAGetErrorInfo is cryptic, so this&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- &amp;nbsp; &amp;nbsp;function is a place where researched information on errors can be saved&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- &amp;nbsp; &amp;nbsp;for future reference.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;DECLARE&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @ErrorMessage &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @ErrorCode &lt;span style=&quot;color: #0000FF;&quot;&gt;binary&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @&lt;span style=&quot;color: #0000FF;&quot;&gt;Source&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @Description &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @ErrorCode = &lt;span style=&quot;color: #FF00FF;&quot;&gt;convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;binary&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, @ReturnCode&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; &lt;span style=&quot;color: #AF0000;&quot;&gt;sp_OAGetErrorInfo&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @&lt;span style=&quot;color: #0000FF;&quot;&gt;Object&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @&lt;span style=&quot;color: #0000FF;&quot;&gt;Source&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;OUTPUT&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @Description &lt;span style=&quot;color: #0000FF;&quot;&gt;OUTPUT&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Context = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Coalesce&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF00FF;&quot;&gt;NullIf&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Context, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, @&lt;span style=&quot;color: #0000FF;&quot;&gt;Source&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;OLE Unknown Source&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;@ErrorMessage = &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #FF00FF;&quot;&gt;IsNull&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@&lt;span style=&quot;color: #0000FF;&quot;&gt;Source&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;OLE Unknown Source&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; Error &#039;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;IsNull&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;0x&#039;&lt;/span&gt; + dbo.&lt;span style=&quot;color: #202020;&quot;&gt;BinaryToHex&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@ErrorCode&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;0x???????&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; - &#039;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;Coalesce&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;Descr, &lt;span style=&quot;color: #FF00FF;&quot;&gt;LTrim&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Description&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Unknown Error&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; Error = @ErrorCode&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; E &lt;span style=&quot;color: #FF00FF;&quot;&gt;LEFT&lt;/span&gt; JOIN &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; Error = &lt;span style=&quot;color: #FF00FF;&quot;&gt;convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;binary&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, 0x80004005&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, Descr = &lt;span style=&quot;color: #FF00FF;&quot;&gt;convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Invalid OLE object handle: The specified handle value (&#039;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, @&lt;span style=&quot;color: #0000FF;&quot;&gt;Object&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;) does not refer to a valid OLE object.&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80010108, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;The object invoked has disconnected from its clients: The previously valid referenced object has closed or stopped running since the last reference.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80020003, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Invalid property or method: property or method &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; was not found&#039;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;IsNull&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; on OLE object of type &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @ObjectType + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;.&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;.&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80020005, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Type mismatch: data type of a Transact-SQL local variable used to store a return value of property or method &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; did not match the Visual Basic data type of the property or method return value. Or, the return value of property or method &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; was requested, but it does not return a value.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80020006, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Unknown name: property or method &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; was not found for the specified object&#039;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;IsNull&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @ObjectType + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;.&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;, + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;.&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80020008, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Bad variable type: data type of a Transact-SQL value passed as a method parameter was NULL or did not match the Microsoft&amp;#174; Visual Basic&amp;#174; method parameter data type.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x8002000B, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Subscript out of range&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; on property or method &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF00FF;&quot;&gt;IsNull&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; of object type &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @ObjectType, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;.&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x8002000E, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Invalid number of parameters on property or method &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF00FF;&quot;&gt;IsNull&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; of object type &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @ObjectType, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;.&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80020011, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Does not support a collection&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; on property or method &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF00FF;&quot;&gt;IsNull&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; of object type &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @ObjectType, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;.&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80040220, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;The &amp;quot;SendUsing&amp;quot; configuration value is invalid.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80080005, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Server execution failed: OLE object &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; is registered as a local OLE server (.exe file) but the .exe file could not be found or started.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80040154, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Class &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; not registered.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x800401F3, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Invalid class string: OLE object ProgID/CLSID &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; is not registered on Server &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;@@ServerName&lt;/span&gt; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;. OLE automation servers need to be registered before they can be instantiated using sp_OACreate. This can be done using regsvr32.exe for inprocess (.dll) servers, or the /REGSERVER command-line switch for local (.exe) servers.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x8004275B, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;sp_OACreate - data type (&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;) or value &#039;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;IsNull&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;(&#039;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;Convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;8000&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, @&lt;span style=&quot;color: #0000FF;&quot;&gt;Value&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;)&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; of parameter &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;context&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; is invalid. Valid context parameter values are 1, 4, and 5.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80042727, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;sp_OASetProperty - improper usage: parameters are ObjPointer int IN, PropertyName varchar IN, @setval &amp;lt;any&amp;gt; IN [, additional indexing IN params].&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80042731, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Output values of type Object require output parameters of type int.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80042732, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Output values of type Object are not allowed in result sets. Use a variable for parameter &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;returnvalue&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; with the OUTPUT keyword in order to return a handle to an object.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x80042742, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Traversal string: &amp;nbsp;Bad whitespace: Error parsing method or property specification string &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;.&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;UNION&lt;/span&gt; ALL &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; 0x8007007E, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;Module could not be found: OLE object &#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt; + @Context + &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #FF0000;&quot;&gt;&#039; is registered as an in-process OLE server (.dll file), but the .dll file could not be found or loaded.&#039;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &amp;nbsp;X &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt; E.&lt;span style=&quot;color: #202020;&quot;&gt;Error&lt;/span&gt; = X.&lt;span style=&quot;color: #202020;&quot;&gt;Error&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;RETURN&lt;/span&gt; @ErrorMessage&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb91375&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb71844&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;CREATE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;FUNCTION&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#91;&lt;/span&gt;dbo&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#93;&lt;/span&gt;.&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#91;&lt;/span&gt;NumberToHex&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#93;&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Number &lt;span style=&quot;color: #0000FF;&quot;&gt;sql_variant&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;RETURNS&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;72&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Written by Erik E&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Converts a value to its hex string representation&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;DECLARE&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @Hex &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;72&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @Pos &lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @Num &lt;span style=&quot;color: #0000FF;&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;38&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; @HexChar &lt;span style=&quot;color: #0000FF;&quot;&gt;tinyint&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Pos = &lt;span style=&quot;color: #FF00FF;&quot;&gt;DataLength&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Number&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; * &lt;span style=&quot;color: #000;&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Num = &lt;span style=&quot;color: #FF00FF;&quot;&gt;convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;38&lt;/span&gt;,&lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, @Number&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHILE&lt;/span&gt; @Pos &amp;gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @HexChar = @Num - &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF00FF;&quot;&gt;Floor&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Num / &lt;span style=&quot;color: #FF00FF;&quot;&gt;Convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;38&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;16&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; * &lt;span style=&quot;color: #FF00FF;&quot;&gt;Convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;38&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;16&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #000;&quot;&gt;48&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Hex = &lt;span style=&quot;color: #0000FF;&quot;&gt;Char&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@HexChar + &lt;span style=&quot;color: #0000FF;&quot;&gt;CASE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;WHEN&lt;/span&gt; @HexChar &amp;gt;= &lt;span style=&quot;color: #000;&quot;&gt;58&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;THEN&lt;/span&gt; &lt;span style=&quot;color: #000;&quot;&gt;7&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;ELSE&lt;/span&gt; &lt;span style=&quot;color: #000;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; + &lt;span style=&quot;color: #FF00FF;&quot;&gt;IsNull&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Hex, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&#039;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Num = &lt;span style=&quot;color: #FF00FF;&quot;&gt;Floor&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Num / &lt;span style=&quot;color: #000;&quot;&gt;16&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; @Pos = @Pos - &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;RETURN&lt;/span&gt; @Hex&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb3656&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb77541&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;CREATE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;FUNCTION&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#91;&lt;/span&gt;dbo&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#93;&lt;/span&gt;.&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#91;&lt;/span&gt;BinaryToHex&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#93;&lt;/span&gt; &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;@Number &lt;span style=&quot;color: #0000FF;&quot;&gt;varbinary&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;RETURNS&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;varchar&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;72&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Written by Erik E&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- Converts varbinary to its hex string representation&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;span style=&quot;color: #0000FF;&quot;&gt;RETURN&lt;/span&gt; dbo.&lt;span style=&quot;color: #202020;&quot;&gt;NumberToHex&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #FF00FF;&quot;&gt;Convert&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;int&lt;/span&gt;, @Number&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;END&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb41477&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here&#039;s a sample execution of SendMail for you:&lt;/p&gt;
&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb8858&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; SendMail &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;emtucifor@example.com&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;emtucifor@example.com&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;This is a test email&#039;&lt;/span&gt;, @HTMLBody = &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;&amp;lt;8000 characters here&amp;gt;&#039;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb31940&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you are sending email to someone who uses Outlook, it helps to provide both TextBody and HTMLBody, because the TextBody is used in the pop-up preview window of the content, so if the person is present when the email arrives, the preview will work correctly.&lt;/p&gt;

&lt;p&gt;I hope that you benefit from this brief but intended-to-be-thorough write-up on exceeding the 8000-character limitation in SQL 2000.&lt;/p&gt;

&lt;p&gt;Erik&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/sql-2000-when-8000-characters-is-not-eno&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://lessthandot.com/&quot;&gt;LessThanDot&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>MS SQL Server 2000 has a limitation of 8000 characters in a varchar variable. The historical reason for this limitation, I believe, is related to the 8k size of data pages, where in-row data can't exceed something like 8060 bytes (actual numbers vary a little).</p>

<p>But what if you need to work with data that is longer than 8000 characters? When storing data in a table, you can use the text datatype which is stored out-of-row (though there are options about storing strings shorter than 8k characters in-row and then moving them out-of-row if they grow). But you can't use the text datatype as a variable. Look:</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb74446'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb74446','cb62445'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb74446" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">DECLARE</span> @longdata <span style="color: #0000FF;">text</span></li></ol></div><div id="cb62445" style="display: none; color: red;"></div></div></div>
<blockquote><p><span class="MT_red">Msg 2739, Level 16, State 1, Line 1<br />
The text, ntext, and image data types are invalid for local variables.</span></p></blockquote>
<p>But while that seems definitive, it is not the whole story, because you <strong>can </strong>use the text data type as a parameter in a stored procedure:</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb56110'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb56110','cb99422'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb56110" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">PROCEDURE</span> DisplayText @longdata <span style="color: #0000FF;">text</span></li><li style="" class="li2"><span style="color: #0000FF;">AS</span></li><li style="" class="li1"><span style="color: #0000FF;">SELECT</span> @longdata</li></ol></div><div id="cb99422" style="display: none; color: red;"></div></div></div>
<p>This works fine, but there are limitations on what can be done with that @longdata variable just like there are with text columns, such as the inability to use the Len() function (use DataLength instead).</p>

<p>If you truly must have variables with more than 8000 characters in a stored procedure, but they can't be passed in as parameters, then you are now in the unfortunate position of having to use tables and text pointers. You'll need the functions TEXTPTR, WRITETEXT, UPDATETEXT, and READTEXT. With these, you can work with pieces of the long data types (no longer than 8000 characters at a time in a variable).</p>

<p>Here's an example of putting more than 8000 characters into a column in an SP:</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb84328'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb84328','cb8305'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb84328" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">TABLE</span> #Table <span style="color: #808080;">&#40;</span></li><li style="" class="li2">&nbsp; &nbsp;id <span style="color: #0000FF;">int</span> <span style="color: #0000FF;">identity</span><span style="color: #808080;">&#40;</span><span style="color: #000;">1</span>,<span style="color: #000;">1</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">primary</span> <span style="color: #0000FF;">key</span> <span style="color: #0000FF;">clustered</span>,</li><li style="" class="li1">&nbsp; &nbsp;longdata <span style="color: #0000FF;">text</span></li><li style="" class="li2"><span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #0000FF;">INSERT</span> #Table <span style="color: #808080;">&#40;</span>longdata<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">VALUES</span> <span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'data to be added to-&gt;'</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #0000FF;">INSERT</span> #Table <span style="color: #808080;">&#40;</span>longdata<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">VALUES</span> <span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'more data-&gt;'</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #0000FF;">DECLARE</span></li><li style="" class="li2">&nbsp; &nbsp;@id <span style="color: #0000FF;">int</span>,</li><li style="" class="li1">&nbsp; &nbsp;@chunknum <span style="color: #0000FF;">int</span>,</li><li style="" class="li2">&nbsp; &nbsp;@ptr <span style="color: #0000FF;">varbinary</span><span style="color: #808080;">&#40;</span><span style="color: #000;">16</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li1">&nbsp; &nbsp;@textchunk <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">SET</span> @id = <span style="color: #000;">0</span></li><li style="" class="li1"><span style="color: #0000FF;">WHILE</span> <span style="color: #000;">1</span> = <span style="color: #000;">1</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">SELECT</span> <span style="color: #0000FF;">TOP</span> <span style="color: #000;">1</span> @id = id, @ptr = <span style="color: #FF00FF;">TextPtr</span><span style="color: #808080;">&#40;</span>longdata<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">FROM</span> #Table <span style="color: #0000FF;">WHERE</span> id &gt; @id <span style="color: #0000FF;">ORDER</span> <span style="color: #0000FF;">BY</span> id</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">IF</span> <span style="color: #FF00FF;">@@RowCount</span> = <span style="color: #000;">0</span> <span style="color: #0000FF;">BREAK</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @chunknum = <span style="color: #000;">1</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">WHILE</span> @chunknum &lt;= <span style="color: #000;">5</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @textchunk = <span style="color: #FF00FF;">Replicate</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">Char</span><span style="color: #808080;">&#40;</span><span style="color: #000;">96</span> + @chunknum<span style="color: #808080;">&#41;</span>, <span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UPDATETEXT</span> #Table.<span style="color: #202020;">longdata</span> @ptr NULL NULL @textchunk</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @chunknum = @chunknum + <span style="color: #000;">1</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">END</span></li><li style="" class="li2"><span style="color: #0000FF;">END</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #0000FF;">SELECT</span> * <span style="color: #0000FF;">FROM</span> #Table</li><li style="" class="li1"><span style="color: #0000FF;">DROP</span> <span style="color: #0000FF;">TABLE</span> #Table</li></ol></div><div id="cb8305" style="display: none; color: red;"></div></div></div>
<p>You can see that you have to loop over each row, and then loop over each chunk of data you want to read from or write to the column.</p>

<p>Now you know the basics of handling more than 8000 characters in SQL 2000. But there are a few subtle things you should know:</p>

<p>&#8226; The 8000-character limitation does not apply to literal strings, just variables and rowsets. This means that with the DisplayText stored procedure above you can put in more than 8000 characters like so:</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb16830'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb16830','cb74628'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb16830" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">EXEC</span> DisplayText <span style="color: #FF0000;">'&lt;more than 8000 characters here&gt;'</span></li></ol></div><div id="cb74628" style="display: none; color: red;"></div></div></div>
<p>This does not mean you can somehow exceed 8000 characters with a commonly-tried but mistaken method such as</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb41470'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb41470','cb82397'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb41470" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">SELECT</span> <span style="color: #FF00FF;">Left</span><span style="color: #808080;">&#40;</span>longdata, <span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF00FF;">Substring</span><span style="color: #808080;">&#40;</span>longdata, <span style="color: #000;">8001</span>, <span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF00FF;">Substring</span><span style="color: #808080;">&#40;</span>longdata, <span style="color: #000;">16001</span>, <span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span></li></ol></div><div id="cb82397" style="display: none; color: red;"></div></div></div>
<p>Sure, this may actually temporarily create a longer string (I don't know for sure) but the final value in the rowset will not exceed 8000 characters.</p>

<p>You can concatenate strings when submitting dynamic SQL statements:</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb10191'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb10191','cb48707'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb10191" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">DECLARE</span></li><li style="" class="li2">&nbsp; &nbsp;@SQL1 <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li1">&nbsp; &nbsp;@SQL2 <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li2">&nbsp; &nbsp;@SQL3 <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li1">&nbsp; &nbsp;@SQL4 <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #0000FF;">SET</span> @SQl1 = <span style="color: #FF0000;">'8000 characters here'</span></li><li style="" class="li2"><span style="color: #0000FF;">SET</span> @SQl2 = <span style="color: #FF0000;">'8000 characters here'</span></li><li style="" class="li1"><span style="color: #0000FF;">SET</span> @SQl3 = <span style="color: #FF0000;">'8000 characters here'</span></li><li style="" class="li2"><span style="color: #0000FF;">SET</span> @SQl4 = <span style="color: #FF0000;">'8000 characters here'</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #0000FF;">EXEC</span> <span style="color: #808080;">&#40;</span>@SQL1 + @SQL2 + @SQL3 + @SQL4<span style="color: #808080;">&#41;</span></li></ol></div><div id="cb48707" style="display: none; color: red;"></div></div></div>
<p>While I can't really recommend this method, if you are desperate and this is the only way to get the job done, it's a possibility. I've personally only used it in two narrow situations: creating pre-processed SQL objects where the dynamic SQL is executed rarely only when something changes, and the code it creates is static until the next change. One creates history-keeping triggers, and the other builds a standard set of pivoted views in response to changes of the metadata definitions of some web objects. Both required this method to be able to handle the number of columns possible. </p>

<p>&#8226; SQL 2005 has a new 'max' keyword for the length of the (n)var/char data types that allows variables to be as big as the (n)text datatype can be. You can do anything to them that you could with regular varchar types, but behind the scenes they function like the text data type with values less than 8000 characters in-row and values greater than 8000 characters stored in out-of-row pages.</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb93714'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb93714','cb79127'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb93714" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">DECLARE</span> @longdata <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">max</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">SET</span> @longdata = <span style="color: #FF0000;">'&lt;more than 8000 characters here&gt;'</span></li></ol></div><div id="cb79127" style="display: none; color: red;"></div></div></div>
<p>Max here simply means that the data type can go up to the maximum storage size allowed, which is 2^31-1 bytes (minus 2 more bytes for presumably a length value). Note that you can't specify varchar(16000) or some value over 8000. You only get between 1 and 8000, or the special identifier <em>max</em>.</p>

<p>As a practical example of using a text datatype to defeat the 8000-character limitation in MS SQL Server 2000, here is a SendMail stored procedure that will use the CDO.Message object to send email with a body longer than 8000 characters. Note: put in your mail server name or make it a parameter or perhaps make it read from a table!</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb35661'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb35661','cb63911'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb35661" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">PROCEDURE</span> SendMail</li><li style="" class="li2">&nbsp; &nbsp;@<span style="color: #0000FF;">From</span> <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">1000</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li1">&nbsp; &nbsp;@<span style="color: #0000FF;">To</span> <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">1000</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li2">&nbsp; &nbsp;@Subject <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">1000</span><span style="color: #808080;">&#41;</span> = <span style="color: #FF0000;">'No Subject'</span>,</li><li style="" class="li1">&nbsp; &nbsp;@TextBody <span style="color: #0000FF;">text</span> = NULL,</li><li style="" class="li2">&nbsp; &nbsp;@HtmlBody <span style="color: #0000FF;">text</span> = NULL</li><li style="" class="li1"><span style="color: #0000FF;">AS</span></li><li style="" class="li2"><span style="color: #00AF00;">-- Written by Erik E</span></li><li style="" class="li1"><span style="color: #00AF00;">-- Sends an email using the CDO.Message object and the SP_OA procedures.</span></li><li style="" class="li2"><span style="color: #00AF00;">-- Notably, accepts text input for emails longer than 8000 characters.</span></li><li style="" class="li1"><span style="color: #0000FF;">DECLARE</span></li><li style="" class="li2">&nbsp; &nbsp;@CDOMessage <span style="color: #0000FF;">int</span>,</li><li style="" class="li1">&nbsp; &nbsp;@ReturnCode <span style="color: #0000FF;">int</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #0000FF;">SET</span> @ReturnCode = <span style="color: #000;">0</span> </li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OACREATE</span> <span style="color: #FF0000;">'CDO.Message'</span>, @CDOMessage <span style="color: #0000FF;">OUT</span></li><li style="" class="li2"><span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'CDO.Message'</span>, NULL, NULL<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OASETPROPERTY</span> @CDOMessage, <span style="color: #FF0000;">'From'</span>, @<span style="color: #0000FF;">From</span></li><li style="" class="li1"><span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'From'</span>, <span style="color: #FF0000;">'CDO.Message'</span>, @<span style="color: #0000FF;">From</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OASETPROPERTY</span> @CDOMessage, <span style="color: #FF0000;">'To'</span>, @<span style="color: #0000FF;">To</span></li><li style="" class="li2"><span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'To'</span>, <span style="color: #FF0000;">'CDO.Message'</span>, @<span style="color: #0000FF;">To</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OASETPROPERTY</span> @CDOMessage, <span style="color: #FF0000;">'Subject'</span>, @Subject</li><li style="" class="li1"><span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'Subject'</span>, <span style="color: #FF0000;">'CDO.Message'</span>, @Subject<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #0000FF;">IF</span> @TextBody <span style="color: #0000FF;">IS</span> NOT NULL <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OASETPROPERTY</span> @CDOMessage, <span style="color: #FF0000;">'TextBody'</span>, @TextBody</li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'TextBody'</span>, <span style="color: #FF0000;">'CDO.Message'</span>, <span style="color: #FF00FF;">Convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>, @TextBody<span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li2"><span style="color: #0000FF;">END</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #0000FF;">IF</span> @HtmlBody <span style="color: #0000FF;">IS</span> NOT NULL <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OASETPROPERTY</span> @CDOMessage, <span style="color: #FF0000;">'HtmlBody'</span>, @HtmlBody</li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'HtmlBody'</span>, <span style="color: #FF0000;">'CDO.Message'</span>, <span style="color: #FF00FF;">Convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>, @HtmlBody<span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li1"><span style="color: #0000FF;">END</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OASETPROPERTY</span> @CDOMessage, <span style="color: #FF0000;">'Configuration.Fields(&quot;http://schemas.microsoft.com/cdo/configuration/sendusing&quot;).Value'</span>, <span style="color: #FF0000;">'2'</span></li><li style="" class="li2"><span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'Configuration.Fields(&quot;http://schemas.microsoft.com/cdo/configuration/sendusing&quot;).Value'</span>, <span style="color: #FF0000;">'CDO.Message'</span>, <span style="color: #FF0000;">'2'</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OASETPROPERTY</span> @CDOMessage, <span style="color: #FF0000;">'Configuration.Fields(&quot;http://schemas.microsoft.com/cdo/configuration/smtpserver&quot;).Value'</span>, <span style="color: #FF0000;">'YourMailServerName'</span></li><li style="" class="li1"><span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'Configuration.Fields(&quot;http://schemas.microsoft.com/cdo/configuration/smtpserver&quot;).Value'</span>, <span style="color: #FF0000;">'CDO.Message'</span>, <span style="color: #FF0000;">'YourMailServerName'</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OASETPROPERTY</span> @CDOMessage, <span style="color: #FF0000;">'Configuration.Fields(&quot;http://schemas.microsoft.com/cdo/configuration/smtpserverport&quot;).Value'</span>, <span style="color: #FF0000;">'25'</span></li><li style="" class="li2"><span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'Configuration.Fields(&quot;http://schemas.microsoft.com/cdo/configuration/smtpserverport&quot;).Value'</span>, <span style="color: #FF0000;">'CDO.Message'</span>, <span style="color: #FF0000;">'25'</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OAMETHOD</span> @CDOMessage, <span style="color: #FF0000;">'Configuration.Fields.Update'</span></li><li style="" class="li1"><span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'Configuration.Fields.Update'</span>, <span style="color: #FF0000;">'CDO.Message'</span>, NULL<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OAMETHOD</span> @CDOMessage, <span style="color: #FF0000;">'Send'</span></li><li style="" class="li2"><span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'Send'</span>, <span style="color: #FF0000;">'CDO.Message'</span>, NULL<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">GOTO</span> Err <span style="color: #0000FF;">END</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2">Err:</li><li style="" class="li1"><span style="color: #0000FF;">SET</span> @ReturnCode = <span style="color: #000;">0</span></li><li style="" class="li2"><span style="color: #0000FF;">IF</span> @CDOMessage &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">EXEC</span> @ReturnCode = <span style="color: #AF0000;">SP_OADESTROY</span> @CDOMessage</li><li style="" class="li1"><span style="color: #0000FF;">IF</span> @ReturnCode &lt;&gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span> <span style="color: #0000FF;">PRINT</span> dbo.<span style="color: #202020;">ObjectErrorFunc</span><span style="color: #808080;">&#40;</span>@CDOMessage, @ReturnCode, <span style="color: #FF0000;">'CDO.Message'</span>, NULL, NULL<span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">END</span></li></ol></div><div id="cb63911" style="display: none; color: red;"></div></div></div>
<p>The error handling here after each SP_OA SP call uses a custom function I wrote. I found it to be invaluable when debugging problems with OLE calls to various objects from SQL Server. You may either tear out this error handling, call the sp_OAGetErrorInfo procedure yourself, or use mine, which is below (plus a couple of dependent functions that you may want to rewrite/modify/reimplement/stop using).</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb24845'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb24845','cb66823'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb24845" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">FUNCTION</span> <span style="color: #808080;">&#91;</span>dbo<span style="color: #808080;">&#93;</span>.<span style="color: #808080;">&#91;</span>ObjectErrorFunc<span style="color: #808080;">&#93;</span> <span style="color: #808080;">&#40;</span></li><li style="" class="li2">&nbsp; &nbsp;@<span style="color: #0000FF;">Object</span> <span style="color: #0000FF;">int</span>,</li><li style="" class="li1">&nbsp; &nbsp;@ReturnCode <span style="color: #0000FF;">int</span>,</li><li style="" class="li2">&nbsp; &nbsp;@Context <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">1000</span><span style="color: #808080;">&#41;</span>, <span style="color: #00AF00;">-- Property or Method</span></li><li style="" class="li1">&nbsp; &nbsp;@ObjectType <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>, <span style="color: #00AF00;">-- Object Name, when known</span></li><li style="" class="li2">&nbsp; &nbsp;@<span style="color: #0000FF;">Value</span> <span style="color: #0000FF;">sql_variant</span> <span style="color: #00AF00;">-- Parameter value, if known</span></li><li style="" class="li1"><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">RETURNS</span> <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #0000FF;">AS</span></li><li style="" class="li2"><span style="color: #00AF00;">-- Written by Erik E</span></li><li style="" class="li1"><span style="color: #00AF00;">-- Makes (more) sense out of error codes when using the OLE sp_OA procedures.</span></li><li style="" class="li2"><span style="color: #00AF00;">-- Sometimes the message returned by sp_OAGetErrorInfo is cryptic, so this</span></li><li style="" class="li1"><span style="color: #00AF00;">-- &nbsp; &nbsp;function is a place where researched information on errors can be saved</span></li><li style="" class="li2"><span style="color: #00AF00;">-- &nbsp; &nbsp;for future reference.</span></li><li style="" class="li1"><span style="color: #0000FF;">BEGIN</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">DECLARE</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; @ErrorMessage <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; @ErrorCode <span style="color: #0000FF;">binary</span><span style="color: #808080;">&#40;</span><span style="color: #000;">4</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; @<span style="color: #0000FF;">Source</span> <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; @Description <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @ErrorCode = <span style="color: #FF00FF;">convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">binary</span><span style="color: #808080;">&#40;</span><span style="color: #000;">4</span><span style="color: #808080;">&#41;</span>, @ReturnCode<span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">EXEC</span> <span style="color: #AF0000;">sp_OAGetErrorInfo</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; @<span style="color: #0000FF;">Object</span>,</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; @<span style="color: #0000FF;">Source</span> <span style="color: #0000FF;">OUTPUT</span>,</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; @Description <span style="color: #0000FF;">OUTPUT</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @Context = <span style="color: #FF00FF;">Coalesce</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">NullIf</span><span style="color: #808080;">&#40;</span>@Context, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span>, @<span style="color: #0000FF;">Source</span>, <span style="color: #FF0000;">'OLE Unknown Source'</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SELECT</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@ErrorMessage = </li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF00FF;">IsNull</span><span style="color: #808080;">&#40;</span>@<span style="color: #0000FF;">Source</span>, <span style="color: #FF0000;">'OLE Unknown Source'</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; + <span style="color: #FF0000;">' Error '</span> + <span style="color: #FF00FF;">IsNull</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'0x'</span> + dbo.<span style="color: #202020;">BinaryToHex</span><span style="color: #808080;">&#40;</span>@ErrorCode<span style="color: #808080;">&#41;</span>, <span style="color: #FF0000;">'0x???????'</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; + <span style="color: #FF0000;">' - '</span> + <span style="color: #FF00FF;">Coalesce</span><span style="color: #808080;">&#40;</span>Descr, <span style="color: #FF00FF;">LTrim</span><span style="color: #808080;">&#40;</span>@Description<span style="color: #808080;">&#41;</span>, <span style="color: #FF0000;">'Unknown Error'</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">FROM</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #808080;">&#40;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SELECT</span> Error = @ErrorCode</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #808080;">&#41;</span> E <span style="color: #FF00FF;">LEFT</span> JOIN <span style="color: #808080;">&#40;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SELECT</span> Error = <span style="color: #FF00FF;">convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">binary</span><span style="color: #808080;">&#40;</span><span style="color: #000;">4</span><span style="color: #808080;">&#41;</span>, 0x80004005<span style="color: #808080;">&#41;</span>, Descr = <span style="color: #FF00FF;">convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>, <span style="color: #FF0000;">'Invalid OLE object handle: The specified handle value ('</span> + <span style="color: #FF00FF;">convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>, @<span style="color: #0000FF;">Object</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF0000;">') does not refer to a valid OLE object.'</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80010108, <span style="color: #FF0000;">'The object invoked has disconnected from its clients: The previously valid referenced object has closed or stopped running since the last reference.'</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80020003, <span style="color: #FF0000;">'Invalid property or method: property or method '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF0000;">''</span><span style="color: #FF0000;">' was not found'</span> + <span style="color: #FF00FF;">IsNull</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">' on OLE object of type '</span><span style="color: #FF0000;">''</span> + @ObjectType + <span style="color: #FF0000;">'.'</span><span style="color: #FF0000;">''</span>, <span style="color: #FF0000;">'.'</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80020005, <span style="color: #FF0000;">'Type mismatch: data type of a Transact-SQL local variable used to store a return value of property or method '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF0000;">''</span><span style="color: #FF0000;">' did not match the Visual Basic data type of the property or method return value. Or, the return value of property or method '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF0000;">''</span><span style="color: #FF0000;">' was requested, but it does not return a value.'</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80020006, <span style="color: #FF0000;">'Unknown name: property or method '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF0000;">''</span><span style="color: #FF0000;">' was not found for the specified object'</span> + <span style="color: #FF00FF;">IsNull</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">' '</span><span style="color: #FF0000;">''</span> + @ObjectType + <span style="color: #FF0000;">'.'</span><span style="color: #FF0000;">''</span>, + <span style="color: #FF0000;">'.'</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80020008, <span style="color: #FF0000;">'Bad variable type: data type of a Transact-SQL value passed as a method parameter was NULL or did not match the Microsoft&#174; Visual Basic&#174; method parameter data type.'</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x8002000B, <span style="color: #FF0000;">''</span><span style="color: #FF0000;">'Subscript out of range'</span><span style="color: #FF0000;">' on property or method '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF00FF;">IsNull</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">' of object type '</span><span style="color: #FF0000;">''</span> + @ObjectType, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF0000;">'.'</span><span style="color: #FF0000;">''</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x8002000E, <span style="color: #FF0000;">'Invalid number of parameters on property or method '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF00FF;">IsNull</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">' of object type '</span><span style="color: #FF0000;">''</span> + @ObjectType, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF0000;">'.'</span><span style="color: #FF0000;">''</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80020011, <span style="color: #FF0000;">''</span><span style="color: #FF0000;">'Does not support a collection'</span><span style="color: #FF0000;">' on property or method '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF00FF;">IsNull</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">''</span><span style="color: #FF0000;">' of object type '</span><span style="color: #FF0000;">''</span> + @ObjectType, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF0000;">'.'</span><span style="color: #FF0000;">''</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80040220, <span style="color: #FF0000;">'The &quot;SendUsing&quot; configuration value is invalid.'</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80080005, <span style="color: #FF0000;">'Server execution failed: OLE object '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF0000;">''</span><span style="color: #FF0000;">' is registered as a local OLE server (.exe file) but the .exe file could not be found or started.'</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80040154, <span style="color: #FF0000;">'Class '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF0000;">''</span><span style="color: #FF0000;">' not registered.'</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x800401F3, <span style="color: #FF0000;">'Invalid class string: OLE object ProgID/CLSID '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF0000;">''</span><span style="color: #FF0000;">' is not registered on Server '</span><span style="color: #FF0000;">''</span> + <span style="color: #FF00FF;">@@ServerName</span> + <span style="color: #FF0000;">''</span><span style="color: #FF0000;">'. OLE automation servers need to be registered before they can be instantiated using sp_OACreate. This can be done using regsvr32.exe for inprocess (.dll) servers, or the /REGSERVER command-line switch for local (.exe) servers.'</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x8004275B, <span style="color: #FF0000;">'sp_OACreate - data type ('</span> + @Context + <span style="color: #FF0000;">') or value '</span> + <span style="color: #FF00FF;">IsNull</span><span style="color: #808080;">&#40;</span><span style="color: #FF0000;">'('</span> + <span style="color: #FF00FF;">Convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">8000</span><span style="color: #808080;">&#41;</span>, @<span style="color: #0000FF;">Value</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF0000;">')'</span>, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF0000;">' of parameter '</span><span style="color: #FF0000;">'context'</span><span style="color: #FF0000;">' is invalid. Valid context parameter values are 1, 4, and 5.'</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80042727, <span style="color: #FF0000;">'sp_OASetProperty - improper usage: parameters are ObjPointer int IN, PropertyName varchar IN, @setval &lt;any&gt; IN [, additional indexing IN params].'</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80042731, <span style="color: #FF0000;">'Output values of type Object require output parameters of type int.'</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80042732, <span style="color: #FF0000;">'Output values of type Object are not allowed in result sets. Use a variable for parameter '</span><span style="color: #FF0000;">'returnvalue'</span><span style="color: #FF0000;">' with the OUTPUT keyword in order to return a handle to an object.'</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x80042742, <span style="color: #FF0000;">'Traversal string: &nbsp;Bad whitespace: Error parsing method or property specification string '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF0000;">'.'</span><span style="color: #FF0000;">''</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">UNION</span> ALL <span style="color: #0000FF;">SELECT</span> 0x8007007E, <span style="color: #FF0000;">'Module could not be found: OLE object '</span><span style="color: #FF0000;">''</span> + @Context + <span style="color: #FF0000;">''</span><span style="color: #FF0000;">' is registered as an in-process OLE server (.dll file), but the .dll file could not be found or loaded.'</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #808080;">&#41;</span> &nbsp;X <span style="color: #0000FF;">ON</span> E.<span style="color: #202020;">Error</span> = X.<span style="color: #202020;">Error</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">RETURN</span> @ErrorMessage</li><li style="" class="li2"><span style="color: #0000FF;">END</span></li></ol></div><div id="cb66823" style="display: none; color: red;"></div></div></div>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb16315'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb16315','cb54999'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb16315" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">FUNCTION</span> <span style="color: #808080;">&#91;</span>dbo<span style="color: #808080;">&#93;</span>.<span style="color: #808080;">&#91;</span>NumberToHex<span style="color: #808080;">&#93;</span> <span style="color: #808080;">&#40;</span>@Number <span style="color: #0000FF;">sql_variant</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">RETURNS</span> <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">72</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #0000FF;">AS</span></li><li style="" class="li2"><span style="color: #00AF00;">-- Written by Erik E</span></li><li style="" class="li1"><span style="color: #00AF00;">-- Converts a value to its hex string representation</span></li><li style="" class="li2"><span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">DECLARE</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; @Hex <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">72</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; @Pos <span style="color: #0000FF;">int</span>,</li><li style="" class="li2">&nbsp; &nbsp; &nbsp; @Num <span style="color: #0000FF;">decimal</span><span style="color: #808080;">&#40;</span><span style="color: #000;">38</span>, <span style="color: #000;">0</span><span style="color: #808080;">&#41;</span>,</li><li style="" class="li1">&nbsp; &nbsp; &nbsp; @HexChar <span style="color: #0000FF;">tinyint</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @Pos = <span style="color: #FF00FF;">DataLength</span><span style="color: #808080;">&#40;</span>@Number<span style="color: #808080;">&#41;</span> * <span style="color: #000;">2</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">SET</span> @Num = <span style="color: #FF00FF;">convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">decimal</span><span style="color: #808080;">&#40;</span><span style="color: #000;">38</span>,<span style="color: #000;">0</span><span style="color: #808080;">&#41;</span>, @Number<span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">WHILE</span> @Pos &gt; <span style="color: #000;">0</span> <span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @HexChar = @Num - <span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">Floor</span><span style="color: #808080;">&#40;</span>@Num / <span style="color: #FF00FF;">Convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">decimal</span><span style="color: #808080;">&#40;</span><span style="color: #000;">38</span>, <span style="color: #000;">0</span><span style="color: #808080;">&#41;</span>, <span style="color: #000;">16</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span> * <span style="color: #FF00FF;">Convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">decimal</span><span style="color: #808080;">&#40;</span><span style="color: #000;">38</span>, <span style="color: #000;">0</span><span style="color: #808080;">&#41;</span>, <span style="color: #000;">16</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span> + <span style="color: #000;">48</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @Hex = <span style="color: #0000FF;">Char</span><span style="color: #808080;">&#40;</span>@HexChar + <span style="color: #0000FF;">CASE</span> <span style="color: #0000FF;">WHEN</span> @HexChar &gt;= <span style="color: #000;">58</span> <span style="color: #0000FF;">THEN</span> <span style="color: #000;">7</span> <span style="color: #0000FF;">ELSE</span> <span style="color: #000;">0</span> <span style="color: #0000FF;">END</span><span style="color: #808080;">&#41;</span> + <span style="color: #FF00FF;">IsNull</span><span style="color: #808080;">&#40;</span>@Hex, <span style="color: #FF0000;">''</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @Num = <span style="color: #FF00FF;">Floor</span><span style="color: #808080;">&#40;</span>@Num / <span style="color: #000;">16</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp; &nbsp; &nbsp; <span style="color: #0000FF;">SET</span> @Pos = @Pos - <span style="color: #000;">1</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">END</span></li><li style="" class="li2">&nbsp; &nbsp;<span style="color: #0000FF;">RETURN</span> @Hex</li><li style="" class="li1"><span style="color: #0000FF;">END</span></li></ol></div><div id="cb54999" style="display: none; color: red;"></div></div></div>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb31046'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb31046','cb29026'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb31046" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">FUNCTION</span> <span style="color: #808080;">&#91;</span>dbo<span style="color: #808080;">&#93;</span>.<span style="color: #808080;">&#91;</span>BinaryToHex<span style="color: #808080;">&#93;</span> <span style="color: #808080;">&#40;</span>@Number <span style="color: #0000FF;">varbinary</span><span style="color: #808080;">&#40;</span><span style="color: #000;">32</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">RETURNS</span> <span style="color: #0000FF;">varchar</span><span style="color: #808080;">&#40;</span><span style="color: #000;">72</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #0000FF;">AS</span></li><li style="" class="li2"><span style="color: #00AF00;">-- Written by Erik E</span></li><li style="" class="li1"><span style="color: #00AF00;">-- Converts varbinary to its hex string representation</span></li><li style="" class="li2"><span style="color: #0000FF;">BEGIN</span></li><li style="" class="li1">&nbsp; &nbsp;<span style="color: #0000FF;">RETURN</span> dbo.<span style="color: #202020;">NumberToHex</span><span style="color: #808080;">&#40;</span><span style="color: #FF00FF;">Convert</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">int</span>, @Number<span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #0000FF;">END</span></li></ol></div><div id="cb29026" style="display: none; color: red;"></div></div></div>
<p>Here's a sample execution of SendMail for you:</p>
<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb59617'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb59617','cb91603'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb59617" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #0000FF;">EXEC</span> SendMail <span style="color: #FF0000;">'emtucifor@example.com'</span>, <span style="color: #FF0000;">'emtucifor@example.com'</span>, <span style="color: #FF0000;">'This is a test email'</span>, @HTMLBody = <span style="color: #FF0000;">'&lt;8000 characters here&gt;'</span></li></ol></div><div id="cb91603" style="display: none; color: red;"></div></div></div>
<p>If you are sending email to someone who uses Outlook, it helps to provide both TextBody and HTMLBody, because the TextBody is used in the pop-up preview window of the content, so if the person is present when the email arrives, the preview will work correctly.</p>

<p>I hope that you benefit from this brief but intended-to-be-thorough write-up on exceeding the 8000-character limitation in SQL 2000.</p>

<p>Erik</p><div class="item_footer"><p><small><a href="http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/sql-2000-when-8000-characters-is-not-eno">Original post</a> blogged on <a href="http://lessthandot.com/">LessThanDot</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/MSSQLServer/sql-2000-when-8000-characters-is-not-eno#comments</comments>
			<wfw:commentRss>http://blogs.lessthandot.com/index.php/DataMgmt/?tempskin=_rss2&#38;disp=comments&#38;p=386</wfw:commentRss>
		</item>
				<item>
			<title>What To Do When Your Identity Column Maxes Out</title>
			<link>http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/MSSQLServerAdmin/what-to-do-when-your-identity-column-max</link>
			<pubDate>Fri, 06 Mar 2009 22:27:51 +0000</pubDate>			<dc:creator>Erik</dc:creator>
			<category domain="main">Microsoft SQL Server Admin</category>			<guid isPermaLink="false">354@http://blogs.lessthandot.com/</guid>
						<description>&lt;p&gt;You have an identity column in your database that was created as int identity(1,1). But after a good few years you are approaching the limit for a signed four-byte long integer, 2147483647. What do you do? Switch the column to bigint?&lt;/p&gt;

&lt;p&gt;Not yet!&lt;/p&gt;

&lt;p&gt;You do something like this:&lt;/p&gt;

&lt;div class=&quot;codebox&quot;&gt;&lt;div class=&quot;codeheader&quot;&gt;Code: &lt;span&gt;tsql&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;codeholder&quot;&gt;&lt;div class=&quot;tsql&quot; id=&quot;cb20402&quot; style=&quot;display: block; color: rgb(0, 0, 0);&quot;&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;--What&#039;s the biggest signed four-byte long:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;--select power(convert(bigint, 2), 31) - 1&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;--2147483647&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;--what your table looks like&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;CREATE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;TABLE&lt;/span&gt; tester &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; testerid &lt;span style=&quot;color: #0000FF;&quot;&gt;INT&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;IDENTITY&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; not null &lt;span style=&quot;color: #0000FF;&quot;&gt;CONSTRAINT&lt;/span&gt; pk_tester &lt;span style=&quot;color: #0000FF;&quot;&gt;PRIMARY&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;KEY&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;CLUSTERED&lt;/span&gt;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; descr &lt;span style=&quot;color: #0000FF;&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- simulate the identity column being near the end of its life (only 32 more rows will fit)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;DBCC&lt;/span&gt; checkident&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;tester, reseed, &lt;span style=&quot;color: #000;&quot;&gt;2147483616&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- push the identity column to its absolute limit&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;INSERT&lt;/span&gt; tester &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #FF00FF;&quot;&gt;CONVERT&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, newid&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;WHILE&lt;/span&gt; &lt;span style=&quot;color: #FF00FF;&quot;&gt;@@ROWCOUNT&lt;/span&gt; &amp;lt; &lt;span style=&quot;color: #000;&quot;&gt;16&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #0000FF;&quot;&gt;INSERT&lt;/span&gt; tester &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #FF00FF;&quot;&gt;CONVERT&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, newid&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; tester&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; * &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; tester&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- you can see that you can&#039;t insert another one like so:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- insert tester select convert(varchar(100), newid())&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;--Redefine the identity column by moving tables in and out.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- * would have to drop referential constraints temporarily&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- * but you can generate script to drop and recreate referential constraints&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- move the table out of the way of the new table&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;EXEC&lt;/span&gt; &lt;span style=&quot;color: #AF0000;&quot;&gt;SP_RENAME&lt;/span&gt; &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;tester&#039;&lt;/span&gt;, &lt;span style=&quot;color: #FF0000;&quot;&gt;&#039;oldtester&#039;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;ALTER&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;TABLE&lt;/span&gt; oldtester &lt;span style=&quot;color: #0000FF;&quot;&gt;DROP&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;CONSTRAINT&lt;/span&gt; pk_tester&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- create the new table with identity set to crawl downward from 0&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;CREATE&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;TABLE&lt;/span&gt; tester &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; testerid &lt;span style=&quot;color: #0000FF;&quot;&gt;INT&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;IDENTITY&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;1&lt;/span&gt;, &lt;span style=&quot;color: #000;&quot;&gt;-1&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; not null &lt;span style=&quot;color: #0000FF;&quot;&gt;CONSTRAINT&lt;/span&gt; pk_tester &lt;span style=&quot;color: #0000FF;&quot;&gt;PRIMARY&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;KEY&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;CLUSTERED&lt;/span&gt;, &lt;span style=&quot;color: #00AF00;&quot;&gt;-- I have no idea why it&#039;s not identity(0, -1), but it&#039;s not.&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; descr &lt;span style=&quot;color: #0000FF;&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- insert the data from the old table&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;IDENTITY_INSERT&lt;/span&gt; tester &lt;span style=&quot;color: #0000FF;&quot;&gt;ON&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;INSERT&lt;/span&gt; tester &lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;testerid, descr&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; testerid, descr &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; oldtester&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SET&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;IDENTITY_INSERT&lt;/span&gt; tester &lt;span style=&quot;color: #0000FF;&quot;&gt;OFF&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- insert some rows so we can see if it works&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;INSERT&lt;/span&gt; tester &lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; &lt;span style=&quot;color: #FF00FF;&quot;&gt;CONVERT&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;VARCHAR&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #000;&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;, newid&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;span style=&quot;color: #808080;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; tester&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- and it works! New rows will start at 0 and count downward to -1, -2, and so on.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;SELECT&lt;/span&gt; * &lt;span style=&quot;color: #0000FF;&quot;&gt;FROM&lt;/span&gt; tester&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style=&quot;color: #00AF00;&quot;&gt;-- clean up&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;DROP&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;TABLE&lt;/span&gt; tester&lt;br /&gt;&lt;span style=&quot;color: #0000FF;&quot;&gt;DROP&lt;/span&gt; &lt;span style=&quot;color: #0000FF;&quot;&gt;TABLE&lt;/span&gt; oldtester&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div id=&quot;cb31462&quot; style=&quot;display: none; color: red;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With this solution, you can keep your database going for another few years, or for about as long as it took you to fill up the positive integers. Then you&#039;ll have to switch to bigints or a decimal data type, though I have to express my disgust for using a packed data type as a clustered index key, especially considering that compared to int or bigint, decimal always uses more bytes of storage for the same precision:&lt;/p&gt;

&lt;p&gt;int: 8-9 digits, up to 4294967296 = 4 bytes storage&lt;br /&gt;
decimal: 9 digits = 5 bytes storage&lt;br /&gt;
bigint: 19-20 digits, up to 18446744073709551616 = 8 bytes storage&lt;br /&gt;
decimal: 10-19 digits = 9 bytes storage&lt;br /&gt;
decimal: 20-28 digits = 13 bytes storage&lt;br /&gt;
decimal: 29-38 digits = 17 bytes storage&lt;/p&gt;

&lt;p&gt;So you can see that bigint is far superior to decimal until you get to 20 digits, supporting up to 18.4 quintillion unique values, which is a heck of a lot, for less than decimal would take to get you there.&lt;/p&gt;&lt;div class=&quot;item_footer&quot;&gt;&lt;p&gt;&lt;small&gt;&lt;a href=&quot;http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/MSSQLServerAdmin/what-to-do-when-your-identity-column-max&quot;&gt;Original post&lt;/a&gt; blogged on &lt;a href=&quot;http://lessthandot.com/&quot;&gt;LessThanDot&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;&lt;/div&gt;</description>
			<content:encoded><![CDATA[<p>You have an identity column in your database that was created as int identity(1,1). But after a good few years you are approaching the limit for a signed four-byte long integer, 2147483647. What do you do? Switch the column to bigint?</p>

<p>Not yet!</p>

<p>You do something like this:</p>

<div class="codebox"><div class="codeheader"><span>tsql</span><div class="codebox_javascript_links"><a href="http://blogs.lessthandot.com" onclick="linenumberOnOff('cb95259'); return false;">Line number Off</a> | <a href="http://blogs.lessthandot.com#" onclick="expandCode('cb95259','cb97943'); return false;">Hide</a> | <a href="http://blogs.lessthandot.com#" onclick="selectCode(this); return false;">Select all</a></div></div><!-- we need this dummy div to fix a firefox bug when selecting code lines --><div class="codeholder"><div class="tsql" id="cb95259" style="display: block; color: rgb(0, 0, 0);"><ol><li style="" class="li1"><span style="color: #00AF00;">--What's the biggest signed four-byte long:</span></li><li style="" class="li2"><span style="color: #00AF00;">--select power(convert(bigint, 2), 31) - 1</span></li><li style="" class="li1"><span style="color: #00AF00;">--2147483647</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #00AF00;">--what your table looks like</span></li><li style="" class="li2"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">TABLE</span> tester <span style="color: #808080;">&#40;</span></li><li style="" class="li1">&nbsp; &nbsp; testerid <span style="color: #0000FF;">INT</span> <span style="color: #0000FF;">IDENTITY</span><span style="color: #808080;">&#40;</span><span style="color: #000;">1</span>, <span style="color: #000;">1</span><span style="color: #808080;">&#41;</span> not null <span style="color: #0000FF;">CONSTRAINT</span> pk_tester <span style="color: #0000FF;">PRIMARY</span> <span style="color: #0000FF;">KEY</span> <span style="color: #0000FF;">CLUSTERED</span>,</li><li style="" class="li2">&nbsp; &nbsp; descr <span style="color: #0000FF;">VARCHAR</span><span style="color: #808080;">&#40;</span><span style="color: #000;">100</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #00AF00;">-- simulate the identity column being near the end of its life (only 32 more rows will fit)</span></li><li style="" class="li1"><span style="color: #0000FF;">DBCC</span> checkident<span style="color: #808080;">&#40;</span>tester, reseed, <span style="color: #000;">2147483616</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #00AF00;">-- push the identity column to its absolute limit</span></li><li style="" class="li2"><span style="color: #0000FF;">INSERT</span> tester <span style="color: #0000FF;">SELECT</span> <span style="color: #FF00FF;">CONVERT</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">VARCHAR</span><span style="color: #808080;">&#40;</span><span style="color: #000;">100</span><span style="color: #808080;">&#41;</span>, newid<span style="color: #808080;">&#40;</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #0000FF;">WHILE</span> <span style="color: #FF00FF;">@@ROWCOUNT</span> &lt; <span style="color: #000;">16</span></li><li style="" class="li2">&nbsp; &nbsp; <span style="color: #0000FF;">INSERT</span> tester <span style="color: #0000FF;">SELECT</span> <span style="color: #FF00FF;">CONVERT</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">VARCHAR</span><span style="color: #808080;">&#40;</span><span style="color: #000;">100</span><span style="color: #808080;">&#41;</span>, newid<span style="color: #808080;">&#40;</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">FROM</span> tester</li><li style="" class="li1"><span style="color: #0000FF;">SELECT</span> * <span style="color: #0000FF;">FROM</span> tester</li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #00AF00;">-- you can see that you can't insert another one like so:</span></li><li style="" class="li2"><span style="color: #00AF00;">-- insert tester select convert(varchar(100), newid())</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #00AF00;">--Redefine the identity column by moving tables in and out.</span></li><li style="" class="li1"><span style="color: #00AF00;">-- * would have to drop referential constraints temporarily</span></li><li style="" class="li2"><span style="color: #00AF00;">-- * but you can generate script to drop and recreate referential constraints</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #00AF00;">-- move the table out of the way of the new table</span></li><li style="" class="li1"><span style="color: #0000FF;">EXEC</span> <span style="color: #AF0000;">SP_RENAME</span> <span style="color: #FF0000;">'tester'</span>, <span style="color: #FF0000;">'oldtester'</span></li><li style="" class="li2"><span style="color: #0000FF;">ALTER</span> <span style="color: #0000FF;">TABLE</span> oldtester <span style="color: #0000FF;">DROP</span> <span style="color: #0000FF;">CONSTRAINT</span> pk_tester</li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #00AF00;">-- create the new table with identity set to crawl downward from 0</span></li><li style="" class="li1"><span style="color: #0000FF;">CREATE</span> <span style="color: #0000FF;">TABLE</span> tester <span style="color: #808080;">&#40;</span></li><li style="" class="li2">&nbsp; &nbsp; testerid <span style="color: #0000FF;">INT</span> <span style="color: #0000FF;">IDENTITY</span><span style="color: #808080;">&#40;</span><span style="color: #000;">1</span>, <span style="color: #000;">-1</span><span style="color: #808080;">&#41;</span> not null <span style="color: #0000FF;">CONSTRAINT</span> pk_tester <span style="color: #0000FF;">PRIMARY</span> <span style="color: #0000FF;">KEY</span> <span style="color: #0000FF;">CLUSTERED</span>, <span style="color: #00AF00;">-- I have no idea why it's not identity(0, -1), but it's not.</span></li><li style="" class="li1">&nbsp; &nbsp; descr <span style="color: #0000FF;">VARCHAR</span><span style="color: #808080;">&#40;</span><span style="color: #000;">100</span><span style="color: #808080;">&#41;</span></li><li style="" class="li2"><span style="color: #808080;">&#41;</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #00AF00;">-- insert the data from the old table</span></li><li style="" class="li1"><span style="color: #0000FF;">SET</span> <span style="color: #0000FF;">IDENTITY_INSERT</span> tester <span style="color: #0000FF;">ON</span></li><li style="" class="li2"><span style="color: #0000FF;">INSERT</span> tester <span style="color: #808080;">&#40;</span>testerid, descr<span style="color: #808080;">&#41;</span></li><li style="" class="li1"><span style="color: #0000FF;">SELECT</span> testerid, descr <span style="color: #0000FF;">FROM</span> oldtester</li><li style="" class="li2"><span style="color: #0000FF;">SET</span> <span style="color: #0000FF;">IDENTITY_INSERT</span> tester <span style="color: #0000FF;">OFF</span></li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #00AF00;">-- insert some rows so we can see if it works</span></li><li style="" class="li1"><span style="color: #0000FF;">INSERT</span> tester <span style="color: #0000FF;">SELECT</span> <span style="color: #FF00FF;">CONVERT</span><span style="color: #808080;">&#40;</span><span style="color: #0000FF;">VARCHAR</span><span style="color: #808080;">&#40;</span><span style="color: #000;">100</span><span style="color: #808080;">&#41;</span>, newid<span style="color: #808080;">&#40;</span><span style="color: #808080;">&#41;</span><span style="color: #808080;">&#41;</span> <span style="color: #0000FF;">FROM</span> tester</li><li style="" class="li2">&nbsp;</li><li style="" class="li1"><span style="color: #00AF00;">-- and it works! New rows will start at 0 and count downward to -1, -2, and so on.</span></li><li style="" class="li2"><span style="color: #0000FF;">SELECT</span> * <span style="color: #0000FF;">FROM</span> tester</li><li style="" class="li1">&nbsp;</li><li style="" class="li2"><span style="color: #00AF00;">-- clean up</span></li><li style="" class="li1"><span style="color: #0000FF;">DROP</span> <span style="color: #0000FF;">TABLE</span> tester</li><li style="" class="li2"><span style="color: #0000FF;">DROP</span> <span style="color: #0000FF;">TABLE</span> oldtester</li></ol></div><div id="cb97943" style="display: none; color: red;"></div></div></div>
<p>With this solution, you can keep your database going for another few years, or for about as long as it took you to fill up the positive integers. Then you'll have to switch to bigints or a decimal data type, though I have to express my disgust for using a packed data type as a clustered index key, especially considering that compared to int or bigint, decimal always uses more bytes of storage for the same precision:</p>

<p>int: 8-9 digits, up to 4294967296 = 4 bytes storage<br />
decimal: 9 digits = 5 bytes storage<br />
bigint: 19-20 digits, up to 18446744073709551616 = 8 bytes storage<br />
decimal: 10-19 digits = 9 bytes storage<br />
decimal: 20-28 digits = 13 bytes storage<br />
decimal: 29-38 digits = 17 bytes storage</p>

<p>So you can see that bigint is far superior to decimal until you get to 20 digits, supporting up to 18.4 quintillion unique values, which is a heck of a lot, for less than decimal would take to get you there.</p><div class="item_footer"><p><small><a href="http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/MSSQLServerAdmin/what-to-do-when-your-identity-column-max">Original post</a> blogged on <a href="http://lessthandot.com/">LessThanDot</a>.</small></p></div>]]></content:encoded>
								<comments>http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/MSSQLServerAdmin/what-to-do-when-your-identity-column-max#comments</comments>
			<wfw:commentRss>http://blogs.lessthandot.com/index.php/DataMgmt/?tempskin=_rss2&#38;disp=comments&#38;p=354</wfw:commentRss>
		</item>
			</channel>
</rss>
