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

<channel>
	<title>TheUnical Technologies Blog &#187; Stored Procedures</title>
	<atom:link href="http://blog.theunical.com/category/databases/stored-procedures/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.theunical.com</link>
	<description>TheUnical Technologies Official Blog</description>
	<lastBuildDate>Fri, 30 Jul 2010 03:56:03 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>How to retrieve stored procedure return values from TableAdapter</title>
		<link>http://blog.theunical.com/databases/ms-sql-server/how-to-retrieve-stored-procedure-return-values-from-tableadapter/</link>
		<comments>http://blog.theunical.com/databases/ms-sql-server/how-to-retrieve-stored-procedure-return-values-from-tableadapter/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 13:09:44 +0000</pubDate>
		<dc:creator>Steven Robert</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Featured]]></category>
		<category><![CDATA[MS SQL Server]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Stored Procedures]]></category>
		<category><![CDATA[Technology News]]></category>
		<category><![CDATA[stored procedure]]></category>

		<guid isPermaLink="false">http://blog.theunical.com/technology-news/how-to-retrieve-stored-procedure-return-values-from-tableadapter/</guid>
		<description><![CDATA[ 
If you’ve been wondering why you are not able to access stored procedure return values from TableAdapter, here’s the solution for you.
I will use tbTasks table and spInsertTask stored procedure to demonstrate the solution. You can see definitions for both below.
CREATE TABLE dbo.tbTasks
(
 intID INT NOT NULL IDENTITY(1,1),
 strName VARCHAR(100) NOT NULL,
 intPriority INT [...]]]></description>
			<content:encoded><![CDATA[<p><span> </span></p>
<p>If you’ve been wondering why you are not able to access stored procedure return values from TableAdapter, here’s the solution for you.</p>
<p>I will use <span><span>tbTasks </span></span>table and <span><span>spInsertTask </span></span>stored procedure to demonstrate the solution.<span> </span>You can see definitions for both below.</p>
<p><span>CREATE</span><span> <span>TABLE</span> dbo<span>.</span>tbTasks</span></p>
<p><span>(</span></p>
<p><span><span> </span>intID <span>INT</span> <span>NOT</span> <span>NULL</span> <span>IDENTITY</span><span>(</span>1<span>,</span>1<span>),</span></span></p>
<p><span><span> </span>strName <span>VARCHAR</span><span>(</span>100<span>)</span> <span>NOT</span> <span>NULL,</span></span></p>
<p><span><span> </span>intPriority <span>INT</span> <span>NOT</span> <span>NULL,</span></span></p>
<p><span><span> </span>dtDueDate <span>DATETIME</span> <span>NOT</span> <span>NULL</span></span></p>
<p><span>)</span></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p><span>CREATE</span><span> <span>PROCEDURE</span> dbo<span>.</span>spInsertTask</span></p>
<p><span><span> </span><span>(</span></span></p>
<p><span><span> </span>@strName <span>VARCHAR</span><span>(</span>200<span>),</span></span></p>
<p><span><span> </span>@intPriority <span>INT</span><span>,</span></span></p>
<p><span><span> </span>@dtDueDate <span>DATETIME</span></span></p>
<p><span><span> </span><span>)</span></span></p>
<p><span>AS</span></p>
<p><span> </span></p>
<p><span>INSERT</span><span> <span>INTO</span> tbTasks <span>(</span>strName<span>,</span> intPriority<span>,</span> dtDueDate<span>)</span></span></p>
<p><span>VALUES</span><span> <span>(</span>@strName<span>,</span> @intPriority<span>,</span> @dtDueDate<span>)</span></span></p>
<p><span> </span></p>
<p><span>RETURN</span><span> <span>SCOPE_IDENTITY</span><span>()</span></span></p>
<p><span>GO</span></p>
<p><span> </span></p>
<p>Notice that <span><span>tbTasks </span></span>has an identity column named <span><span>intID</span></span>.<span> </span>Also, stored procedure <span><span>spInsertTask </span></span>returns the new identity column value using <a href="http://msdn2.microsoft.com/en-us/library/ms190315(d=ide).aspx"><span><span>SCOPE_IDENTITY()</span></span></a>.<span> </span>Knowing this new identity value is extremely useful on the client side.</p>
<p>Create a new Typed Dataset called <em>TasksDataset</em> and add <span><span>tbTasks</span></span>.<span> </span>Also, add a new query to <em>tbTasksTableAdapter</em> using <span><span>spInsertTask</span></span> stored procedure.<span> </span>When adding a new query, choose ‘A single value’ option.</p>
<p><img src="http://blog.theunical.com/wp-content/plugins/wp-o-matic/cache/383dd_original.aspx" alt="" /></p>
<p><img src="http://blogs.msdn.com/photos/youngjoo/images/693131/original.aspx" alt="" /></p>
<p>At this point, you probably would expect that following code would assign the new identity value returned by <span><span>spInsertTask</span></span> stored procedure to <span><span>returnValue</span></span> variable.</p>
<p>[ VB ]</p>
<p><span>Dim</span><span> taTasks <span>As</span> <span>New</span> TasksDatasetTableAdapters.tbTasksTableAdapter</span></p>
<p><span>Dim</span><span> TaskName <span>As</span> <span>String</span></span></p>
<p><span>Dim</span><span> TaskPriority <span>As</span> <span>Integer</span></span></p>
<p><span>Dim</span><span> TaskDueDate <span>As</span> <span>Date</span></span></p>
<p><span>Dim</span><span> returnValue <span>As</span> <span>Integer</span></span></p>
<p><span> </span></p>
<p><span>TaskName = <span>&#8220;Test&#8221;</span></span></p>
<p><span>TaskPriority = 1</span></p>
<p><span>TaskDueDate = Now()</span></p>
<p><span> </span></p>
<p><span>returnValue = taTasks.InsertTask(TaskName, TaskPriority, TaskDueDate)</span></p>
<p><span> </span></p>
<p>[C#]</p>
<p><span>TasksDatasetTableAdapters.<span>tbTasksTableAdapter</span> taCustomers = <span>new</span> WindowsApplication1.TasksDatasetTableAdapters.<span>tbTasksTableAdapter</span>();</span></p>
<p><span>String</span><span> taskName;</span></p>
<p><span>int</span><span> taskPriority;</span></p>
<p><span>DateTime</span><span> taskDueDate;</span></p>
<p><span>int</span><span> returnValue;</span></p>
<p><span> </span></p>
<p><span>taskName = <span>&#8220;Test&#8221;</span>;</span></p>
<p><span>taskPriority = 1;</span></p>
<p><span>taskDueDate = System.<span>DateTime</span>.Now;</span></p>
<p><span> </span></p>
<p><span>returnValue = taCustomers.InsertTask(taskName, taskPriority, taskDueDate);</span></p>
<p>However, running above code results in <em>System.InvalidOperationException</em> during run-time for VB and “<em>Cannot implicitly convert type &#8216;int?&#8217; to &#8216;int&#8217;</em>.” compile error for C#.<span> </span>If you look at what actually gets returned by <span><span>tbTasksTableAdapter.InsertTask()</span></span> function, you will understand why above code does not work.<span> </span>You can find the function from the generated Typed Dataset code, <em>TasksDataset.Designer.vb</em> / <em>TasksDataset.Designer.cs</em> in this case.</p>
<p>[ VB ]</p>
<p><span>Public</span><span> <span>Overridable</span> <span>Overloads</span> <span>Function</span> InsertTask(&#8230;) <span>As</span> System.Nullable(<span>Of</span> <span>Integer</span>)</span></p>
<p><span><span> </span>&#8230;</span></p>
<p><span><span> </span>&#8230;</span></p>
<p><span><span> </span><span>Dim</span> returnValue <span>As</span> <span>Object</span></span></p>
<p><span><span> </span><span>Try</span></span></p>
<p><span><span> </span>returnValue = command.ExecuteScalar</span></p>
<p><span><span> </span><span>Finally</span></span></p>
<p><span><span> </span>&#8230;</span></p>
<p><span><span> </span><span>End</span> <span>Try</span></span></p>
<p><span><span> </span><span>If</span> ((returnValue <span>Is</span> <span>Nothing</span>) _</span></p>
<p><span><span> </span><span>OrElse</span> (returnValue.GetType <span>Is</span> <span>GetType</span>(System.DBNull))) <span>Then</span></span></p>
<p><span><span> </span><span>Return</span> <span>New</span> System.Nullable(<span>Of</span> <span>Integer</span>)</span></p>
<p><span><span> </span><span>Else</span></span></p>
<p><span><span> </span><span>Return</span> <span>New</span> System.Nullable(<span>Of</span> <span>Integer</span>)(<span>CType</span>(returnValue, <span>Integer</span>))</span></p>
<p><span><span> </span><span>End</span> <span>If</span></span></p>
<p><span>End</span><span> <span>Function</span></span></p>
<p><em><span>* C# version omitted since there’s no significant difference.</span></em></p>
<p><span>As you can see from above, what gets returned from InsertTask function is actually the return value of </span><span><span>System.Data.SqlClient.SqlCommand.ExecuteScalar()</span></span><span> which is <em>the first column of the first row in the result set, or a null reference if the result set is empty</em>, not the return value of the stored procedure.<span> </span>In this case, </span><span><span>InsertTask</span></span><span> returns null since the stored procedure does not return any result set.</span></p>
<p><span>If you choose ‘No value’ option, </span><span><span>System.Data.SqlClient.SqlCommand.ExecuteNonQuery()</span></span><span> is used instead.<span> </span>And the return value of </span><span><span>ExecuteNonQuery()</span></span><span> is <em>the number of rows affected</em>.<span> </span>Again, this is not the stored procedure return value.</span></p>
<p><span>So, how do you retrieve the stored procedure return value?<span> </span>Although it’s not immediately obvious, there’s an easy way to access it.<span> </span>Let’s look at the definition of the command object for the stored procedure.<span> </span>You can see it from </span><span><span>tbTasksTableAdapter.InitCommandCollection()</span></span><span> in </span><em>TasksDataset.Designer.vb</em> / <em>TasksDataset.Designer.cs</em> file.</p>
<p>[ VB]</p>
<p><span>Private</span><span> <span>Sub</span> InitCommandCollection()</span></p>
<p><span><span> </span><span>Me</span>._commandCollection = <span>New</span> System.Data.SqlClient.SqlCommand(1) {}</span></p>
<p><span><span> </span><span>Me</span>._commandCollection(0) = <span>New</span> System.Data.SqlClient.SqlCommand</span></p>
<p><span><span> </span><span>Me</span>._commandCollection(0).Connection = <span>Me</span>.Connection</span></p>
<p><span><span> </span><span>Me</span>._commandCollection(0).CommandText = <span>&#8220;SELECT intID, strName, intPriority, dtDueDate FROM dbo.tbTasks&#8221;</span></span></p>
<p><span><span> </span><span>Me</span>._commandCollection(0).CommandType = System.Data.CommandType.Text</span></p>
<p><span><span> </span><span>Me</span>._commandCollection(1) = <span>New</span> System.Data.SqlClient.SqlCommand</span></p>
<p><span><span> </span><span>Me</span>._commandCollection(1).Connection = <span>Me</span>.Connection</span></p>
<p><span><span> </span><span>Me</span>._commandCollection(1).CommandText = <span>&#8220;dbo.spInsertTask&#8221;</span></span></p>
<p><span><span> </span><span>Me</span>._commandCollection(1).CommandType = System.Data.CommandType.StoredProcedure</span></p>
<p><span><span> </span><span>Me</span>._commandCollection(1).Parameters.Add(<span>New</span> System.Data.SqlClient.SqlParameter(<span>&#8220;@RETURN_VALUE&#8221;</span>, System.Data.SqlDbType.Int, 4, System.Data.ParameterDirection.ReturnValue, 10, 0, <span>Nothing</span>, System.Data.DataRowVersion.Current, <span>false</span>, <span>Nothing</span>, <span>&#8220;&#8221;</span>, <span>&#8220;&#8221;</span>, <span>&#8220;&#8221;</span>))</span></p>
<p><span><span> </span><span>Me</span>._commandCollection(1).Parameters.Add(<span>New</span> System.Data.SqlClient.SqlParameter(<span>&#8220;@strName&#8221;</span>, System.Data.SqlDbType.VarChar, 200, System.Data.ParameterDirection.Input, 0, 0, <span>Nothing</span>, System.Data.DataRowVersion.Current, <span>false</span>, <span>Nothing</span>, <span>&#8220;&#8221;</span>, <span>&#8220;&#8221;</span>, <span>&#8220;&#8221;</span>))</span></p>
<p><span><span> </span><span>Me</span>._commandCollection(1).Parameters.Add(<span>New</span> System.Data.SqlClient.SqlParameter(<span>&#8220;@intPriority&#8221;</span>, System.Data.SqlDbType.Int, 4, System.Data.ParameterDirection.Input, 10, 0, <span>Nothing</span>, System.Data.DataRowVersion.Current, <span>false</span>, <span>Nothing</span>, <span>&#8220;&#8221;</span>, <span>&#8220;&#8221;</span>, <span>&#8220;&#8221;</span>))</span></p>
<p><span><span> </span><span>Me</span>._commandCollection(1).Parameters.Add(<span>New</span> System.Data.SqlClient.SqlParameter(<span>&#8220;@dtDueDate&#8221;</span>, System.Data.SqlDbType.DateTime, 8, System.Data.ParameterDirection.Input, 23, 3, <span>Nothing</span>, System.Data.DataRowVersion.Current, <span>false</span>, <span>Nothing</span>, <span>&#8220;&#8221;</span>, <span>&#8220;&#8221;</span>, <span>&#8220;&#8221;</span>))</span></p>
<p><span>End</span><span> <span>Sub</span></span></p>
<p><em><span>* C# version omitted since there’s no significant difference.</span></em></p>
<p><span>You can see from above that parameters collection does actually include </span><span><span>@RETURN_VALUE</span></span><span> parameter.<span> </span>It’s the first parameter in the collection.<span> </span>When the stored procedure is executed, return value from the stored procedure is added to this item in the collection.<span> </span>So, all we need to do is to retrieve this value after executing </span><span><span>InsertTask()</span></span><span> function.<span> </span>To do that, I will add some code to the partial class defined in <em>TasksDataset.vb / TasksDataset.cs</em>.</span></p>
<p><span>[ VB ]</span></p>
<p><span>Namespace</span><span> TasksDatasetTableAdapters</span></p>
<p><span><span> </span><span>Partial</span> <span>Public</span> <span>Class</span> tbTasksTableAdapter</span></p>
<p><span><span> </span><span>Public</span> <span>Function</span> GetReturnValue(<span>ByVal</span> commandIndex <span>As</span> <span>Integer</span>) <span>As</span> <span>Object</span></span></p>
<p><span><span> </span><span>Return</span> <span>Me</span>.CommandCollection(commandIndex).Parameters(0).Value</span></p>
<p><span><span> </span><span>End</span> <span>Function</span></span></p>
<p><span><span> </span><span>End</span> <span>Class</span></span></p>
<p><span>End</span><span> <span>Namespace</span></span></p>
<p><span> </span></p>
<p><span>[ C# ]</span></p>
<p><span>namespace</span><span> WindowsApplication1.TasksDatasetTableAdapters {</span></p>
<p><span><span> </span><span>public</span> <span>partial</span> <span>class</span> <span>tbTasksTableAdapter</span></span></p>
<p><span><span> </span>{</span></p>
<p><span><span> </span><span>public</span> <span>object</span> GetReturnValue(<span>int</span> commandIndex)</span></p>
<p><span><span> </span>{</span></p>
<p><span><span> </span><span>return</span> <span>this</span>.CommandCollection[commandIndex].Parameters[0].Value;</span></p>
<p><span><span> </span>}</span></p>
<p><span><span> </span>}</span></p>
<p><span>}</span></p>
<p><span> </span></p>
<p><span>Since Dataset Designer does not generate partial class structure for TableAdapters, you will have to add above code yourself to partial class file.<span> </span>The commandIndex parameter is the index of the command object in </span><span><span>_commandCollection</span></span><span> to retrieve return value from.<span> </span>You can get that information by looking at </span><span><span>tbTasksTableAdapter.InitCommandCollection(). </span></span><span>Now, let’s modify the code that was not running to use this new function.</span></p>
<p>[ VB ]</p>
<p><span>Dim</span><span> taTasks <span>As</span> <span>New</span> TasksDatasetTableAdapters.tbTasksTableAdapter</span></p>
<p><span>Dim</span><span> TaskName <span>As</span> <span>String</span></span></p>
<p><span>Dim</span><span> TaskPriority <span>As</span> <span>Integer</span></span></p>
<p><span>Dim</span><span> TaskDueDate <span>As</span> <span>Date</span></span></p>
<p><span>Dim</span><span> returnValue <span>As</span> <span>Integer</span></span></p>
<p><span> </span></p>
<p><span>TaskName = <span>&#8220;Test&#8221;</span></span></p>
<p><span>TaskPriority = 1</span></p>
<p><span>TaskDueDate = Now()</span></p>
<p><span> </span></p>
<p><span>taTasks.InsertTask(TaskName, TaskPriority, TaskDueDate)</span></p>
<p><span>returnValue = taTasks.GetReturnValue(1)</span></p>
<p><span> </span></p>
<p>[C#]</p>
<p><span>TasksDatasetTableAdapters.<span>tbTasksTableAdapter</span> taCustomers = <span>new</span> WindowsApplication1.TasksDatasetTableAdapters.<span>tbTasksTableAdapter</span>();</span></p>
<p><span>String</span><span> taskName;</span></p>
<p><span>int</span><span> taskPriority;</span></p>
<p><span>DateTime</span><span> taskDueDate;</span></p>
<p><span>int</span><span> returnValue;</span></p>
<p><span> </span></p>
<p><span>taskName = <span>&#8220;Test&#8221;</span>;</span></p>
<p><span>taskPriority = 1;</span></p>
<p><span>taskDueDate = System.<span>DateTime</span>.Now;</span></p>
<p><span> </span></p>
<p><span>taCustomers.InsertTask(taskName, taskPriority, taskDueDate);</span></p>
<p><span>returnValue = (int)taCustomers.GetReturnValue(1);</span></p>
<p>We pass in 1 as a parameter value to <span><span>GetReturnValue()</span></span> since our stored procedure is located at index 1 in <span><span>_commandCollection</span></span>.<span> </span>Above code will correctly retrieve return value from the stored procedure which is the new identity value of <span><span>intID</span></span> column.<span> </span>If you have more than one stored procedures that return something, you can retrieve those return values by calling <span><span>GetReturnValue()</span></span> with correct index.</p>
<p>Typed Dataset simplifies data access layer development significantly by generating necessary code for you based on the information you provide via Dataset Designer.<span> </span>Although generated code covers large number of scenarios, I suggest that you take a close look at generated code and find out how you can extend the functionality of default Typed Dataset.<span> </span>And definitely let us know how we can improve it to make Typed Dataset more powerful and flexible.</p>
<p>Also, don’t forget to let me know if you have better ways to retrieve return values from stored procedures.<span> </span>What I suggest here is just one solution and I am sure that you have other solutions that might be more elegant than this.</p>
<p><strong><em>Young Joo</em></strong></p>
<p><img src="http://blog.theunical.com/wp-content/plugins/wp-o-matic/cache/cf921_aggbug.aspx?PostID=693113" alt="" width="1" height="1" /></p>
<img src="http://blog.theunical.com/?ak_action=api_record_view&id=199094&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.theunical.com/databases/ms-sql-server/how-to-retrieve-stored-procedure-return-values-from-tableadapter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Stored Procedures are EVIL</title>
		<link>http://blog.theunical.com/databases/ms-sql-server/stored-procedures-are-evil-2/</link>
		<comments>http://blog.theunical.com/databases/ms-sql-server/stored-procedures-are-evil-2/#comments</comments>
		<pubDate>Wed, 11 Mar 2009 05:39:00 +0000</pubDate>
		<dc:creator>Steven Robert</dc:creator>
				<category><![CDATA[Featured]]></category>
		<category><![CDATA[MS SQL Server]]></category>
		<category><![CDATA[MS SQL Server 2000]]></category>
		<category><![CDATA[MS SQL Server 2005]]></category>
		<category><![CDATA[MS SQL Server 2008]]></category>
		<category><![CDATA[MySQL 5.1]]></category>
		<category><![CDATA[MySql]]></category>
		<category><![CDATA[MySql 5.0]]></category>
		<category><![CDATA[Stored Procedures]]></category>

		<guid isPermaLink="false">http://rachasatish.wordpress.com/2009/03/11/stored-procedures-are-evil/</guid>
		<description><![CDATA[
&#160;
Stored Procedures are EVIL
By Tony Marston
3rd September 2006
A lot of developers are taught to use database stored procedures, triggers and database constraints at every possible opportunity, and they cannot understand why an old dinosaur like me should choose to take an opposite view. The reason can be summed up quite simply:
You only know what you [...]]]></description>
			<content:encoded><![CDATA[<div class="Section1">
<p class="MsoNormal">&nbsp;</p>
<h1>Stored Procedures are EVIL</h1>
<h2>By Tony Marston</h2>
<p>3rd September 2006</p>
<p>A lot of developers are taught to use database stored procedures, triggers and database constraints at every possible opportunity, and they cannot understand why an old dinosaur like me should choose to take an opposite view. The reason can be summed up quite simply:</p>
<p class="MsoNormal"><i>You</i> only know what you have been taught, whereas <i>I</i> know what I have learned. </p>
<p>I was weaned on file systems and databases which did not have any facilities for stored procedures and triggers, so I learned how to build applications without them. When such facilities became available my colleagues and I still never used them for practical reasons:</p>
<ul type="disc">
<li class="MsoNormal">It meant learning a new language, and we didn&#8217;t      have the time.</li>
<li class="MsoNormal">It meant taking longer to implement and maintain,      therefore cost more to develop. This is an important consideration for a      software house which can only win business by providing cost-effective      solutions.</li>
<li class="MsoNormal">There was no advantage in doing so, so why      bother?</li>
</ul>
<p>Our golden rule was:</p>
<p class="MsoNormal">Use stored procedures and triggers only when it is an <i>absolutely</i> necessity. </p>
<p>This is in total conflict with the attitude of today&#8217;s wet-behind-the-ears tenderfoot greenhorn who seems to think:</p>
<p class="MsoNormal">Use stored procedures and triggers at every possible opportunity simply because you can. </p>
<div class="MsoNormal" align="center" style='text-align:center;'>
<hr size="2" width="100%" align="center">  </div>
<p>Amongst the arguments in favour of stored procedures are:</p>
<h4>Stored procedures are not as brittle as dynamic SQL</h4>
<p>Some people argue that putting ad-hoc SQL in your business layer (BL) code is not that good. Agreed, but who said that the only alternative is stored procedures? Why not have a DAL that generates the SQL query at runtime based on information passed to it by the BL? It is correct to say that small changes to the database can have severe impacts on the application. However, changes to a relational model will <i>always</i> have an impact on the application that targets that model: add a non-nullable column to a table and you will see what I mean. You can use stored procedures or ad-hoc queries, you have to change the calling code to make sure that column gets a value when a new row is inserted. For Ad-hoc queries, you change the query, and you&#8217;re set. For stored procedures, you have to change the signature of the stored procedure, since the INSERT/UPDATE procs have to receive a value for the new column. This can break other code targeting the stored procedure as well, which is a severe maintenance issue. A component which generates the SQL on the fly at runtime doesn&#8217;t suffer from this: it will for example receive an entity which has to be saved to the database, that entity contains the new field, the SQL is generated and the entity is saved. No maintenance problems. With a stored procedure this wouldn&#8217;t be possible. </p>
<h4>Stored procedures are more secure</h4>
<p>This is a common argument that many people echo without realising that it became defunct when role-based security was made available. A good DBA defines user-roles in the database, and users are added to those roles and rights are defined per role, not per user. This way, it is easy to control which users can insert / update and which users can for example select or delete or have access to views in an easy way.</p>
<p>With a view it is possible to control which data is accessed on a <i>column</i> basis or <i>row</i> basis. This means that if you want user U to select only 2 or so columns from a table, you can give that user access to a view, not the underlying table. The same goes for rows in one or more tables. Create a view which shows those rows, filtering out others. Give access rights to the view, not the table, obviously using user-roles. This way you can limit access to sensitive data without having to compromise your programming model because you have to move to stored procedures.</p>
<p>It is also said that stored procedures are more secure because they prevent SQL injection attacks. This argument is false for the simple reason that it is possible to have a stored procedure which concatenates strings together and therefore open itself up to sql injection attacks (generally seen in systems which use procedures and have to offer some sort of general search routine), while the use of parameterized queries removes this vulnerability as no value can end up as being part of the actually query string.</p>
<h4>Stored procedures are more efficient</h4>
<p>The execution of SQL statements in stored procedures <i>may</i> have been faster than with dynamic SQL in the early days of database systems, but that advantage has all but disappeared in the current versions. In some cases a stored procedure may even be <i>slower</i> than dynamic SQL, so this argument is as dead as a Dodo.</p>
<p>Performance should not be the first question. My belief is that most of the time you should focus on writing maintainable code. Then use a profiler to identify hot spots and then replace only those hot spots with faster but less clear code. The main reason to do this is because in most systems only a very small proportion of the code is actually performance critical, and it&#8217;s much easier to improve the performance of well factored maintainable code.</p>
<p>While stored procedures may run faster, they take longer to build, test, debug and maintain, therefore this extra speed comes at a price. If the same function can be performed inside application code at an acceptable speed, what is the advantage of spending more money to make it run faster at a more-than-acceptable speed? It is OK to use stored procedures when you absolutely need a performance gain, but until then they&#8217;re nothing but premature optimization.</p>
<h4>The company has paid for them, so why not use them?</h4>
<p>A similar argument is that by not using what the company has paid for, you are effectively wasting the company&#8217;s money. I&#8217;m sorry, but using something <i>because it&#8217;s there</i> is just not good enough. If I can achieve something inside my application with application code, then I must be given a very good reason to move it out of my application and into the database. Believe it or not there are costs involved in moving logic from one place to another, and those costs must be offset by measurable benefits.</p>
<h4>Application code or database code &#8211; it&#8217;s still code, isn&#8217;t it?</h4>
<p>No it&#8217;s not. Application code is built using a programming language whereas SQL is nothing more than a data manipulation language, and is therefore very limited in its scope. There is absolutely nothing that can be done in a stored procedure that cannot also be done in application code, but the converse is not true.</p>
<div class="MsoNormal" align="center" style='text-align:center;'>
<hr size="2" width="100%" align="center">  </div>
<p>Amongst the arguments against stored procedures are:</p>
<h4>It mangles the 3 Tier structure</h4>
<p>Instead of having a structure which separates concerns in a tried and trusted way &#8211; GUI, business logic and storage &#8211; you now have logic intermingling with storage, and logic on multiple tiers within the architecture. This causes potential headaches down the road if that logic has to change.</p>
<h4>Stored procedures are a maintenance problem</h4>
<p>The reason for this is that stored procedures form an API by themselves. Changing an API is not that good, it will break a lot of code in some situations. Adding new functionality or new procedures is the &quot;best&quot; way to extend an existing API. A set of stored procedures is no different. This means that when a table changes, or behaviour of a stored procedure changes and it requires a new parameter, a new stored procedure has to be added. This might sound l</p>
<p>ike a minor problem but it isn&#8217;t, especially when your system is already large and has run for some time. Every system developed runs the risk of becoming a legacy system that has to be maintained for several years. This takes a lot of time, because the communication between the developer(s) who maintain/write the stored procedures and the developer(s) who write the DAL/BL code has to be intense: a new stored procedure will be saved fine, however it will not be called correctly until the DAL code is altered. When you have Dynamic SQL in your BL at your hands, it&#8217;s not a problem. You change the code there, create a different filter, whatever you like and whatever fits the functionality to implement.</p>
<p>Microsoft also believes stored procedures are over: it&#8217;s next generation business framework MBF is based on Objectspaces, which generates SQL on the fly.</p>
<h4>Stored procedures take longer to test</h4>
<p>Business logic in stored procedures is more work to test than the corresponding logic in the application. Referential integrity will often force you to setup a lot of other data just to be able to insert the data you need for a test (unless you&#8217;re working in a legacy database without any foreign key constraints). Stored procedures are inherently procedural in nature, and hence harder to create isolated tests and prone to code duplication. Another consideration, and this matters a great deal in a sizable application, is that any automated test that hits the database is slower than a test that runs inside of the application. Slow tests lead to longer feedback cycles.</p>
<h4>BL in stored procedures does not scale</h4>
<p>If all the business logic is held in the database instead of the application then the database becomes the bottleneck. Once the load starts increasing the performance starts dropping. With business logic in the application it is easy to scale up simply by adding another processor or two, but that option is not readily available if all that logic is held in the database.</p>
<p>If you have a system with 100&#8217;s of distributed databases it is far more difficult to keep all those stored procedures and triggers synchronized than it is to keep the application code synchronized.</p>
<h4>Stored procedures are not customisable</h4>
<p>This is a big issue if you want an application where the customer can insert their own business logic, or where different logic is required by different customers. Achieving this with application code is a piece of cake, but with database logic it is a can of worms.</p>
<h4>Database triggers are hidden from the application</h4>
<p>A big problem with database triggers is that the application does not know that they exist, therefore does not know whether they have run or not. This became a serious issue in one application (not written by me) which I was maintaining. A new DBA who was not aware of the existence of all these triggers did something which deactivated every trigger on the main database. The triggers were still there, they had not been deleted, but they had been turned off so did not fire and do what they were supposed to do. This mistake took several hours to spot and several days to fix.</p>
<h4>Version Control</h4>
<p>It is easy to control all changes to application code by running it through a proper version control system, but those facilities do not exist for stored procedures and triggers. How much damage could be caused if a stored procedure were to get out of sync with the application code? How easy is it to check that the application is running with the correct versions? How much more difficult would it be if the application you were supporting was running on a remote site with nothing more than a dial-up connection?</p>
<p>This is a reason why some teams avoid stored procedures like the plague &#8211; it eliminates an area of potentially disastrous screw-ups.</p>
<h4>Vendor lock-in</h4>
<p>You may think that this is not a problem if you build and maintain the applications for a single company where a change in database vendor is highly unlikely, but what happens should the company decide that their DBMS is no longer flavour of the month and they want to change to a different DBMS? This may be due to several factors, such as spiraling costs or poor performance, but when it happens you will find that a lot of code will have to be rewritten. Porting the data will be one exercise, but porting the stored procedures and triggers will be something else entirely. Now, if all that logic were held inside the application, how much simpler would it be?</p>
<p>Believe it or not there are people out there who write applications which are database-independent for the simple reason that the applications may be used by many different companies, and those many companies may not all use the same DBMS. Those that do use the same DBMS may not be using the same version, and stored procedures written for one version may not be compatible with another.</p>
<div class="MsoNormal" align="center" style='text-align:center;'>
<hr size="2" width="100%" align="center">  </div>
<p>As far as I am concerned the use of stored procedures, database triggers and foreign key restraints is OPTIONAL, not MANDATORY, therefore I am free to exercise my option not to use them. That is my choice, and the software that I produce does not suffer in any way, therefore it cannot be defined as the <i>wrong</i> choice.</p>
<p>The <a href="http://www.tonymarston.net/php-mysql/infrastructure.html">web application framework</a> that I have built using PHP does not use stored procedures, database triggers or foreign key constraints, yet it does not suffer from any lack of functionality. This is possible simply because I can do everything I want inside my application where it is instantly accessible and customisable. To those of you who instantly jump to the (wrong) conclusion that this must mean that I have to write a huge amount of duplicated SQL statements my answer is simple &#8211; I don&#8217;t write any SQL statements at all, they are all generated dynamically at runtime. This is all due to the framework being built using the <a href="http://www.tonymarston.net/php-mysql/infrastructure.html#3tier">3 Tier Architecture</a> which has a clear separation of concerns:</p>
<ul type="disc">
<li class="MsoNormal">There is a separate object in the Business Layer      for each database table. This is where all business rules are applied as      data passes from the Presentation Layer (UI), through the Business Layer      to the Data Access Layer, and back again. The Business Layer does not have      any direct communication with the database &#8211; this is all handled by the      Data Access Layer.</li>
<li class="MsoNormal">There is a single object in the Data Access Layer      known as the Data Access Object (DAO). The DAO receives a request from the      Business Layer and dynamically constructs and executes the SQL query      string to satisfy that request. This implementation means that I can      easily switch to another DBMS simply by switching to another DAO, and      without having to change a single line of code in any Business Layer      object.</li>
<li class="MsoNormal">Referential integrity is also handled by standard      code within the framework and requires no additional coding from any      developer whatsoever. It uses information which is exported from the <a href="http://www.tonymarston.net/php-mysql/data-dictionary.html">Data      Dictionary</a> which tells it what to do with every relationship, and the      standard code in the framework simply performs the relevant processing.      The advantage of this approach is that it is easy to amend or even turn      off any of these rules at runtime, which makes the application infinitely      more flexible.</li>
<li class="MsoNormal">All changes made to the database can be logged      without using a single database trigger. How? By adding extra code into      the DAO to write all relevant details out to the AUDIT database. This      functionality is totally transparent to all the objects in the Business      Layer, and they do not need any extra code to make it work
<p>.</li>
</ul>
<div class="MsoNormal" align="center" style='text-align:center;'>
<hr size="2" width="100%" align="center">  </div>
<h2>References</h2>
<ul type="disc">
<li class="MsoNormal"><a href="http://weblogs.asp.net/fbouma/archive/2003/11/18/38178.aspx">Stored      procedures are bad, m&#8217;kay?</a></li>
<li class="MsoNormal"><a href="http://www.javaworld.com/javaworld/jw-01-2000/jw-01-ssj-tiers-p3.html">One,      two, three, or n tiers?</a> (page 3, 7th paragraph)</li>
<li class="MsoNormal"><a href="http://www.martinfowler.com/articles/dblogic.html">Domain Logic and      SQL</a></li>
<li class="MsoNormal"><a href="http://c2.com/cgi/wiki?BusinessLogicInStoredProcedures">Business      Logic In Stored Procedures</a></li>
<li class="MsoNormal"><a href="http://codebetter.com/blogs/jeremy.miller/archive/2006/05/25/145450.aspx">Why      I do not use Stored Procedures</a></li>
<li class="MsoNormal"><a href="http://www.artima.com/weblogs/viewpostP.jsp?thread=128108">Problems      with using stored procedures</a></li>
<li class="MsoNormal"><a href="http://www.theserverside.net/common/printthread.tss?thread_id=31953">Stored      Procedures v Parameterized Queries</a></li>
<li class="MsoNormal"><a href="http://jooto.com/blog/index.php/2005/11/01/the-myth-of-data-integrity">The      Myth Of Data Integrity</a></li>
<li class="MsoNormal"><a href="http://codebetter.com/blogs/peter.van.ooijen/archive/2006/05/29/145697.aspx">I      inherited a database which contains sprocs (and a lot of other BL)</a></li>
<li class="MsoNormal"><a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/07/05/130093.aspx">Good      and Evil in the Garden of Stored Procedures</a></li>
<li class="MsoNormal"><a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/07/06/130094.aspx">Attitudes      towards Stored Procedures</a></li>
<li class="MsoNormal"><a href="http://www.codinghorror.com/blog/archives/000117.html">Who needs      Stored Procedures, anyways?</a></li>
<li class="MsoNormal"><a href="http://www.codinghorror.com/blog/archives/000292.html">Stored      Procedures vs ad-hoc SQL</a></li>
<li class="MsoNormal"><a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/06/09/129562.aspx">The      Worst Possible Way to use a Stored Procedure</a></li>
</ul>
<div class="MsoNormal" align="center" style='text-align:center;'>
<hr size="2" width="100%" align="center">  </div>
<p>&copy; <span class="sig">Tony Marston</span><br /> 3rd September 2006</p>
<p> <a href="http://www.tonymarston.net">http://www.tonymarston.net</a> <br /> <a href="http://www.radicore.org">http://www.radicore.org</a></p>
<p><img border="0" width="62" height="21" src="image001.png@01C9A19E.07531580" alt="counter"></p>
<p class="MsoNormal">&nbsp;</p>
</p></div>
<img src="http://blog.theunical.com/?ak_action=api_record_view&id=232&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://blog.theunical.com/databases/ms-sql-server/stored-procedures-are-evil-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
