<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results matching tags 'Transact SQL' and 'Inline UDFs'</title><link>http://sqlblog.com/search/SearchResults.aspx?o=DateDescending&amp;tag=Transact+SQL,Inline+UDFs&amp;orTags=0</link><description>Search results matching tags 'Transact SQL' and 'Inline UDFs'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Multi-statement TVFs are essentially slowish nested loops.</title><link>http://sqlblog.com/blogs/alexander_kuznetsov/archive/2010/02/02/multiline-tvfs-are-essentially-slowish-nested-loops.aspx</link><pubDate>Tue, 02 Feb 2010 20:53:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:21727</guid><dc:creator>Alexander Kuznetsov</dc:creator><description>&lt;p&gt;Whenever we are using multi-statement TVFs, we are essentially forcing nested loops logic on the database engine. Although multi-statement TVFs are smart enough and do not always execute once per row, when they do so, they may be much slower than nested loops.&lt;/p&gt;&lt;p&gt;As usual, inline UDFs shine as compared to multi-statement ones, at least in all the benchmarks in this post - let us run some tests and see for ourselves. &lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;u&gt;&lt;b&gt;&amp;nbsp;Setting up data&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;First of all, here is a table, rather large, 512K rows, and rather wide, less than 20 rows per page, so that reading from it via nested loops is a natural choice in many cases:&lt;/p&gt;&lt;br&gt;&amp;nbsp;&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;CREATE&amp;nbsp;TABLE&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Parent
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;NOT&amp;nbsp;NULL
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;PRIMARY&amp;nbsp;KEY&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;,
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentNumber&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;NOT&amp;nbsp;NULL,
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;SpaceFiller&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;CHAR&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;500&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;NOT&amp;nbsp;NULL
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;)&amp;nbsp;;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;DECLARE&amp;nbsp;&lt;/span&gt;&lt;span&gt;@adder&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SET&amp;nbsp;&lt;/span&gt;&lt;span&gt;@adder&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;INSERT&amp;nbsp;&amp;nbsp;INTO&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Parent
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentNumber&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;SpaceFiller&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;VALUES&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'#'&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;;
&lt;br&gt;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;WHILE&amp;nbsp;&lt;/span&gt;&lt;span&gt;@adder&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;500000&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;BEGIN&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INSERT&amp;nbsp;&amp;nbsp;INTO&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Parent
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;,
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentNumber&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;,
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;SpaceFiller
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;+&amp;nbsp;&lt;/span&gt;&lt;span&gt;@adder&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;,
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentNumber&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;,
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;SpaceFiller
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Parent&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SET&amp;nbsp;&lt;/span&gt;&lt;span&gt;@adder&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;nbsp;&lt;/span&gt;&lt;span&gt;@adder&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;*&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;2&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;END&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO&lt;/span&gt;&lt;/code&gt;                &amp;nbsp;&amp;nbsp;
              &lt;/p&gt;&lt;p&gt;The Child table is much smaller and narrow: &lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;CREATE&amp;nbsp;TABLE&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Child
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;NOT&amp;nbsp;NULL
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;PRIMARY&amp;nbsp;KEY&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;,
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentID&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;NOT&amp;nbsp;NULL&amp;nbsp;,
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ChildNumber&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;NOT&amp;nbsp;NULL&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNIQUE
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO
&lt;br&gt;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;INSERT&amp;nbsp;INTO&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Child
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ChildNumber&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:green;"&gt;--&amp;nbsp;ID&amp;nbsp;-&amp;nbsp;int
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:green;"&gt;--&amp;nbsp;ParentID&amp;nbsp;-&amp;nbsp;int
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:green;"&gt;--&amp;nbsp;ChildNumber&amp;nbsp;-&amp;nbsp;int
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Parent&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;WHERE&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;BETWEEN&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;AND&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1000&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;&amp;nbsp;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;u&gt;&lt;b&gt;&amp;nbsp;Comparing nested loops vs. multi-statement UDF calls&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Here are the two UDFs which we are&amp;nbsp; going to benchmark:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;CREATE&amp;nbsp;FUNCTION&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.GetParentNumber_Multiline&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span&gt;@ParentID&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;RETURNS&amp;nbsp;&lt;/span&gt;&lt;span&gt;@parentInfo&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;TABLE&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentNumber&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BEGIN&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INSERT&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span&gt;@parentInfo
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentNumber
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentNumber
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Parent
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;WHERE&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;nbsp;&lt;/span&gt;&lt;span&gt;@ParentID&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;RETURN&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;END&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO
&lt;br&gt;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE&amp;nbsp;FUNCTION&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;GetParentNumber_Inline&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span&gt;@ParentID&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;RETURNS&amp;nbsp;TABLE
&lt;br&gt;AS
&lt;br&gt;RETURN
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentNumber
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Parent
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;WHERE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;nbsp;&lt;/span&gt;&lt;span&gt;@ParentID
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;;
&lt;/span&gt;&lt;/code&gt;                &amp;nbsp;
              &lt;/p&gt;&lt;p&gt;Let us fire up the Profiler, make sure it records individual statements, and run the following script:&lt;/p&gt;&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;p.ParentNumber
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;INTO&amp;nbsp;&lt;/span&gt;&lt;span&gt;#t&lt;/span&gt;&lt;span style="color:black;"&gt;1
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Child
&lt;br&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;CROSS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;APPLY&amp;nbsp;dbo.GetParentNumber_Multiline&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentID&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;p&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;DROP&amp;nbsp;TABLE&amp;nbsp;&lt;/span&gt;&lt;span&gt;#t&lt;/span&gt;&lt;span style="color:black;"&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;p.ParentNumber
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;INTO&amp;nbsp;&lt;/span&gt;&lt;span&gt;#t&lt;/span&gt;&lt;span style="color:black;"&gt;1
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Child
&lt;br&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;CROSS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;APPLY&amp;nbsp;dbo.GetParentNumber_Inline&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentID&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;p
&lt;br&gt;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;DROP&amp;nbsp;TABLE&amp;nbsp;&lt;/span&gt;&lt;span&gt;#t&lt;/span&gt;&lt;span style="color:black;"&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;&amp;nbsp;
&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;In the Profiler, we shall see that the multi-statement UDF has been invoked 1000 times, which is slow:&lt;/p&gt;&lt;p&gt;Multiline stats: &lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp; CPU time = 312 ms,&amp;nbsp; elapsed time = 696 ms.&lt;br&gt;&lt;/p&gt;&lt;p&gt;Inline stats:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp; CPU time = 0 ms,&amp;nbsp; elapsed time = 7 ms.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Clearly the difference in performance is dramatic, while the plan is essentially the same - nested loops. We can highlight the query, compare the execution plans, and see for ourselves.&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;u&gt;&lt;b&gt;Multi-statement UDFs do not always run once per row&lt;/b&gt;&lt;/u&gt; &lt;br&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;While we are at it, let us bust a myth: multi-statement UDFs do not have to run once per row. Let us have all child rows refer to only one parent:&lt;/p&gt;&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;UPDATE&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Child&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SET&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentID&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;&amp;nbsp;
&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;Let us rerun our benchmarks. In the profiler we shall see that the multi-statement UDF has been invoked only once. Execution costs are also quite comparable this time for both scripts:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp; CPU time = 15 ms,&amp;nbsp; elapsed time = 21 ms.&lt;br&gt;&lt;/p&gt;&lt;p&gt;As we have seen, the database engine is smart enough and may sometimes execute multi-statement UDFs once per distinct set of parameters, not once per row.&lt;br&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;u&gt;&lt;b&gt;Multi-statement UDFs essentially force nested loops on the engine&lt;/b&gt;&lt;/u&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;Let us set up test data differently, so that the second benchmark (the one using inline UDF) executes as a hash join:&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;UPDATE&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Child&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SET&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentID&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;&amp;nbsp;
&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;TRUNCATE&amp;nbsp;TABLE&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Parent&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO &lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;INSERT&amp;nbsp;INTO&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Parent
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ParentNumber&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;SpaceFiller&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ID&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'*'&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;dbo.Child&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;;
&lt;br&gt;&lt;/span&gt;&lt;/code&gt;                &amp;nbsp;&amp;nbsp;
              &lt;/p&gt;&lt;p&gt;The first benchmark still executes as a nested loop, and is much slower&lt;/p&gt;&lt;p&gt;Multi-statement UDF, nested loops:&lt;br&gt;&amp;nbsp;&amp;nbsp; CPU time = 266 ms,&amp;nbsp; elapsed time = 674 ms.&lt;br&gt;&amp;nbsp; &amp;nbsp;&lt;br&gt;Inline UDF, hash join:&lt;br&gt;&amp;nbsp;&amp;nbsp; CPU time = 0 ms,&amp;nbsp; elapsed time = 5 ms.&lt;br&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;u&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;As we have seen, if we want to force nested loops, we can use multi-statement UDFs.Also we have seen that those multi-statement UDFs can be very slow.&lt;br&gt;&lt;/p&gt;&lt;p&gt;However, let us be cautious: when we want to benchmark real life solutions, we do not want to do it with the Profiler running, like I did in this post. Also, as Dave Ballantine has correctly pointed out, in some cases STATISTICS TIME may skew the results just as well.&lt;br&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description></item><item><title>Calculating third Wednesday of the month with inline UDFs</title><link>http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/06/21/calculating-third-wednesday-of-the-month-with-inline-udfs.aspx</link><pubDate>Mon, 22 Jun 2009 02:06:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:14811</guid><dc:creator>Alexander Kuznetsov</dc:creator><description>&lt;p&gt;Problems such as calculating third Wednesday of the month or the last day of the month are very common. &lt;a href="http://weblogs.sqlteam.com/peterl/archive/2009/06/17/How-to-get-the-Nth-weekday-of-a-month.aspx"&gt;Recently Peter Larsson posted a scalar UDF that solves problems such as "third Wednesday of the month"&lt;/a&gt;, and Uri Dimant added a comment with a solution by Steve Kass. Unfortunately, all these solutions use scalar UDFs and as such are very slow, so I decided to post some very fast inline UDFs that I find very useful.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;b&gt;Composing a date from year, month, and day without checking if the parameters are valid.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;The following inline UDF composes a date. I deliberately intend to use it with invalid parameters, such as month equal to zero, because it dramatically simplifies my logic.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;CREATE FUNCTION&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.ComposeDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span&gt;@year&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@day&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;--&amp;nbsp;I&amp;nbsp;deliberately&amp;nbsp;do&amp;nbsp;not&amp;nbsp;check&amp;nbsp;if&amp;nbsp;the&amp;nbsp;parameters&amp;nbsp;are&amp;nbsp;valid
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;RETURNS&amp;nbsp;TABLE&amp;nbsp;AS&amp;nbsp;RETURN&lt;/span&gt;&lt;span style="color:gray;"&gt;(
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:magenta;"&gt;DATEADD&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:magenta;"&gt;DAY&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@day&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;-&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:magenta;"&gt;DATEADD&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:magenta;"&gt;MONTH&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;-&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:magenta;"&gt;DATEADD&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:magenta;"&gt;YEAR&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@year&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;-&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1901&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'19010101'&lt;/span&gt;&lt;span style="color:gray;"&gt;)))
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate
&lt;br&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO
&lt;br&gt;&lt;/span&gt;&lt;/code&gt;                &amp;nbsp;&amp;nbsp;
              &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;u&gt;&lt;b&gt;Calculating the last days of previous and this months.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Because my ComposeDate function handles out of range parameters, I don't need to handle January and December differently. Here you go, create them and see how they work:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;CREATE&amp;nbsp;FUNCTION&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.LastDayOfPreviousMonth&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span&gt;@year&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;RETURNS&amp;nbsp;TABLE&amp;nbsp;AS&amp;nbsp;RETURN&lt;/span&gt;&lt;span style="color:gray;"&gt;(
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;LastDayOfPreviousMonth
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.ComposeDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span&gt;@year&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;)&amp;nbsp;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;LastDayOfPreviousMonth&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'20081231'&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.LastDayOfPreviousMonth&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNION&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;ALL
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;LastDayOfPreviousMonth&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'20090131'&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.LastDayOfPreviousMonth&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;CREATE&amp;nbsp;FUNCTION&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.LastDayOfMonth&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span&gt;@year&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;RETURNS&amp;nbsp;TABLE&amp;nbsp;AS&amp;nbsp;RETURN&lt;/span&gt;&lt;span style="color:gray;"&gt;(
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;LastDayOfMonth
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.ComposeDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span&gt;@year&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&lt;/span&gt;&lt;span style="color:gray;"&gt;+&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;)&amp;nbsp;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;LastDayOfMonth&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.LastDayOfMonth&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;11&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNION&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;ALL
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;LastDayOfMonth&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.LastDayOfMonth&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;12&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO&amp;nbsp;
&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;u&gt;&lt;b&gt;Calculating third Wednesday and other similar problems&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;For simplicity (this is a blog post, not production code), this function does not determine if the returned date is actually in the required month or in another one. If you need such validation, use the approach demonstrated in the next example.&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;CREATE FUNCTION&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span&gt;@year&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@week&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@day&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;--&amp;nbsp;@day&amp;nbsp;1&amp;nbsp;Sun,&amp;nbsp;2 Mon&amp;nbsp;etc.&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:green;"&gt;--
this function works in US but might need adjustments in other countries&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;RETURNS&amp;nbsp;TABLE&amp;nbsp;AS&amp;nbsp;RETURN&lt;/span&gt;&lt;span style="color:gray;"&gt;(&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;t.ComposedDate&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;MthDayOfNthWeek
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.ComposeDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span&gt;@year&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;))&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;d &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;CROSS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;APPLY&amp;nbsp;Readers.ComposeDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span&gt;@year&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span&gt;@day&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;-&amp;nbsp;&lt;/span&gt;&lt;span style="color:magenta;"&gt;DATEPART&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;dw&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;+ 1 +&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;7&lt;/span&gt;&lt;span style="color:gray;"&gt;*(&lt;/span&gt;&lt;span&gt;@week&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;+&amp;nbsp;&lt;/span&gt;&lt;span style="color:magenta;"&gt;CASE&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;WHEN&amp;nbsp;&lt;/span&gt;&lt;span style="color:magenta;"&gt;DATEPART&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;dw&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;gt;&lt;/span&gt;&lt;span&gt;@day&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;THEN&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;0&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;ELSE&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;-&lt;/span&gt;&lt;span style="color:black;"&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;END&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;)&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;t
&lt;br&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO
&lt;br&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;--&amp;nbsp;third&amp;nbsp;Wednesday&amp;nbsp;of&amp;nbsp;June&amp;nbsp;2009
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'20090617'&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ExpectedDate&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;6&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;3&lt;/span&gt;&lt;span style="color:gray;"&gt;, 4&lt;/span&gt;&lt;span style="color:black;"&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNION&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;ALL
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'20090715'&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ExpectedDate&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;7&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;3&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;4&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNION&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;ALL
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'20090601'&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ExpectedDate&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;6&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNION&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;ALL
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'20090605'&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ExpectedDate&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;6&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;6&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNION&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;ALL
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'20090606'&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ExpectedDate&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;6&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;, 7&lt;/span&gt;&lt;span style="color:black;"&gt;&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNION&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;ALL
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'20090608'&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ExpectedDate&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.MthDayOfNthWeek&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;6&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&amp;nbsp;
&lt;/span&gt;&lt;/code&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;This function is not completely trivial, so I used test driven development to come up with it.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;u&gt;&lt;b&gt;Validating dates&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;If you need to validate dates, use the following approach:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;code style="font-size:12px;"&gt;&lt;span style="color:blue;"&gt;CREATE&amp;nbsp;FUNCTION&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.ComposeValidDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span&gt;@year&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@day&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;INT&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;RETURNS&amp;nbsp;TABLE&amp;nbsp;AS&amp;nbsp;RETURN&lt;/span&gt;&lt;span style="color:gray;"&gt;(
&lt;br&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:magenta;"&gt;CASE&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;WHEN&amp;nbsp;&lt;/span&gt;&lt;span style="color:magenta;"&gt;YEAR&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;nbsp;&lt;/span&gt;&lt;span&gt;@year&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;AND&amp;nbsp;&lt;/span&gt;&lt;span style="color:magenta;"&gt;MONTH&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&lt;/span&gt;&lt;span style="color:gray;"&gt;)&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;=&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&amp;nbsp;
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;THEN&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;END&amp;nbsp;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate
&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.ComposeDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span&gt;@year&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@month&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span&gt;@day&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;)&amp;nbsp;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;GO
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:red;"&gt;'20090228'&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;AS&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ExpectedResult&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.ComposeValidDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;28&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNION&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;ALL&amp;nbsp;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;NULL&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.ComposeValidDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;29&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNION&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;ALL&amp;nbsp;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;NULL&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.ComposeValidDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;)
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;UNION&amp;nbsp;&lt;/span&gt;&lt;span style="color:gray;"&gt;ALL&amp;nbsp;
&lt;br&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;SELECT&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;ComposedDate&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;NULL&amp;nbsp;&lt;/span&gt;&lt;span style="color:blue;"&gt;FROM&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;Readers.ComposeValidDate&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;2009&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style="color:black;"&gt;12&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;/code&gt;                &amp;nbsp;&amp;nbsp;
              &lt;/p&gt;
&lt;p&gt;Only the first result will validate.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;Read more about performance of inline UDFs in &lt;a href="http://www2.sqlblog.com/blogs/alexander_kuznetsov/archive/2008/05/23/reuse-your-code-with-cross-apply.aspx"&gt;"Reuse Your Code with Table-Valued UDFs"&lt;/a&gt; and &lt;a href="http://sqlblog.com/blogs/alexander_kuznetsov/archive/2009/06/18/many-nested-inline-udfs-are-very-fast.aspx"&gt;"Many nested inline UDFs are very fast"&lt;/a&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description></item></channel></rss>