<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Dave's SQL Blog</title>
	
	<link>http://davidbrycehoward.com</link>
	<description>Things I know about SQL worth writing about...</description>
	<lastBuildDate>Fri, 17 Feb 2012 23:30:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/DavesSqlBlog" /><feedburner:info uri="davessqlblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>T-SQL Tuesday #026 – The Wrap Up</title>
		<link>http://feedproxy.google.com/~r/DavesSqlBlog/~3/XSVApZsMDqQ/</link>
		<comments>http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-026-the-wrap-up/#comments</comments>
		<pubDate>Wed, 18 Jan 2012 14:58:35 +0000</pubDate>
		<dc:creator>David Howard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbrycehoward.com/?p=453</guid>
		<description><![CDATA[Thank you everyone who participated in T-SQL Tuesday #026! I really enjoyed hosting and reading all of the contributions. Thanks also to Adam Machanic (blog &#124; @AdamMachanic) for starting this monthly event and for allowing me to run this show &#8230; <a href="http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-026-the-wrap-up/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Thank you everyone who participated in T-SQL Tuesday #026!  I really enjoyed hosting and reading all of the contributions. Thanks also to Adam Machanic (<a href="http://sqlblog.com/blogs/adam_machanic/">blog</a> | <a href="http://twitter.com/adammachanic">@AdamMachanic</a>) for starting this monthly event and for allowing me to run this show this time around.</p>
<p>We had 14 posts, covering about 10 different topics depending on how you count.  Here&#8217;s a brief summary of them all, in the order received.</p>
<p>1. The first post was from Rob Farley (<a href="http://sqlblog.com/blogs/rob_farley/default.aspx">blog</a> | <a href="http://twitter.com/rob_farley">@rob_farley</a>), a T-SQL Tuesday regular and one of my favorite SQL bloggers.<img style="display: inline; float: right" align="right" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/tsqltuesday.gif" width="200" height="200"> He writes about a limitation of using <a href="http://sqlblog.com/blogs/rob_farley/archive/2012/01/10/apply-not-exactly-set-based.aspx">APPLY</a> when dealing with working calculations which he had written about in an <a href="http://sqlblog.com/blogs/rob_farley/archive/2011/12/13/a-t-sql-tip-working-calculations.aspx">earlier post</a>.<br />
Original T-SQL Tuesday <a href="http://mattvelic.com/tsql-tuesday-17-invite/">17</a> / <a href="http://sqlblog.com/blogs/allen_white/archive/2011/12/05/t-sql-tuesday-025-invitation-to-share-your-tricks.aspx">25</a></p>
<p>2. Sebastian Meine (<a href="http://sqlity.net/en/blog/">blog</a> | <a href="http://twitter.com/sqlity">@sqlity</a>) delves into some <a href="http://sqlity.net/en/563/index-misconceptions-tsql-tuesday-026-second-chances/">index internals</a>, explaining SQL Server&#8217;s B+ tree structure, and how that is different from a standard B-Tree.<br />
Original T-SQL Tuesday <a href="http://michaeljswart.com/2010/09/invitation-to-participate-in-t-sql-tuesday-10-indexes/">10</a> / <a href="http://sankarreddy.com/2010/10/invitation-to-participate-in-t-sql-tuesday-11-misconceptions-in-sql-server/">11</a></p>
<p>3. Steve Wales (<a href="http://dba-in-exile.blogspot.com/">blog</a> | <a href="http://twitter.com/walessj">@walessj</a>) tells a <a href="http://dba-in-exile.blogspot.com/2012/01/t-sql-tuesday-14-er-26-second-chances.html">tale</a> of T-SQL Tuesday, managing to incorporate references to all the past 25 events &#8211; very creative!  He also let us in on his 2012 resolutions, which match up with mine in a lot of ways (except for that one with the &#8220;O&#8221; word <img src='http://davidbrycehoward.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  )<br />
Original T-SQL Tuesday <a href="http://www.midnightdba.com/Jen/2011/01/t-sql-tuesday-resolutions/">14</a></p>
<p>4. After a brief intro in French and some cool New Year&#8217;s Eve images, Jason Brimhall (<a href="http://jasonbrimhall.info/">blog</a> | <a href="http://twitter.com/sqlrnnr">@sqlrnnr</a>) covers several type of ways to <a href="http://jasonbrimhall.info/2012/01/10/tsql-tuesday-26-or-23-identity-crisis/">perform JOINs</a> on tables where a bitmask is applied to an id field.<br />
Original T-SQL Tuesday <a href="http://codegumbo.com/index.php/2011/09/27/tsql2sday-t-sql-tuesday-23early-edition/">23</a></p>
<p>5. I enjoyed reading Jason Grobe&#8217;s (<a href="http://jgrobe.wordpress.com/">blog</a> | <a href="http://twitter.com/sqlmental">@sqlmental</a>) <a href="http://jgrobe.wordpress.com/2012/01/09/t-sql-tuesday-026-its-2012-already/">resolutions</a>, which cover both personal, professional and community oriented goals.  More power to you Jason!<br />
Original T-SQL Tuesday <a href="http://www.midnightdba.com/Jen/2011/01/t-sql-tuesday-resolutions/">14</a></p>
<p>6. Nancy Hidy Wilson (<a href="http://nancyhidywilson.wordpress.com/blog/">blog</a> | <a href="http://twitter.com/NancyHidyWilson">@NancyHidyWilson</a>)  extols the <a href="http://nancyhidywilson.wordpress.com/2012/01/10/tsql2sday-026-second-chances/">virtues</a> of her favorite &#8220;new&#8221; features in SQL 2008 R2: CMS (Central Management Server) and PBM (Policy Based Management).<br />
Original T-SQL Tuesday <a href="http://sqlchicken.com/2010/06/t-sql-tuesday-007-summertime-in-the-sql/">7</a></p>
<p>7. Mike Fal (<a href="http://www.mikefal.net/">blog</a> | <a href="http://twitter.com/Mike_Fal">@Mike_Fal</a>) shows a <a href="http://www.mikefal.net/2012/01/10/t-sql-tuesdaytsql2sday-26-lazy-restore-commands/">trick</a> for dynamically generating a restore command using the output of a RESTORE FILELISTONLY command.  Very cool.<br />
Original T-SQL Tuesday <a href="http://sqlblog.com/blogs/allen_white/archive/2011/12/05/t-sql-tuesday-025-invitation-to-share-your-tricks.aspx">25</a></p>
<p>8. Robert Pearl (<a href="http://www.sqlservercentral.com/blogs/pearlknows/">blog</a> | <a href="http://twitter.com/PearlKnows">@PearlKnows</a>) shows us the &#8220;<a href="http://www.sqlservercentral.com/blogs/pearlknows/2012/01/10/t-sql-tuesday-26-second-chances-correlate-missing-index-with-related-query/">best of all worlds</a>&#8221; with a very comprehensive query against the missing index DMVs.<br />
Original T-SQL Tuesday <a href="http://sqlblog.com/blogs/allen_white/archive/2011/12/05/t-sql-tuesday-025-invitation-to-share-your-tricks.aspx">25</a></p>
<p>9. Aaron Bertrand (<a href="http://sqlblog.com/blogs/aaron_bertrand/default.aspx">blog</a> | <a href="http://twitter.com/AaronBertrand">@AaronBertrand</a>) shares some <a href="http://sqlblog.com/blogs/aaron_bertrand/archive/2012/01/10/t-sql-tuesday-26-second-chances.aspx">work</a> he did at a previous job to implement customer time zone logic at the database layer simplifying the presentation to the application.<br />
Original T-SQL Tuesday <a href="http://www.sqlservercentral.com/blogs/pearlknows/2011/09/06/invitation-for-t-sql-tuesday-22-data-presentation/">22</a></p>
<p>10. Steve Jones (<a href="http://voiceofthedba.wordpress.com/">blog</a> | <a href="http://twitter.com/way0utwest">@way0utwest</a>) discusses a <a href="http://voiceofthedba.wordpress.com/2012/01/10/t-sql-tuesday-26-second-changes-with-datetime/">topic</a> I run into all the time reviewing code, how to deal with the time component of a date range correctly.<br />
Original T-SQL Tuesday <a href="http://sqlblog.com/blogs/adam_machanic/archive/2009/11/30/invitation-to-participate-in-t-sql-tuesday-001-date-time-tricks.aspx">1</a></p>
<p>11. Colleen Morrow (<a href="http://colleenmorrow.com/">blog</a> | <a href="http://twitter.com/ClevelandDBA">@ClevelandDBA</a>) shares some of her new year&#8217;s <a href="http://colleenmorrow.com/2012/01/10/tsql-tuesday-026-%E2%80%93-second-chances/">resolutions</a> with us as well as her strategy for keeping up with them.  I really like her idea of breaking them down into monthly chunks so they don&#8217;t seem so daunting.<br />
Original T-SQL Tuesday <a href="http://www.midnightdba.com/Jen/2011/01/t-sql-tuesday-resolutions/">14</a></p>
<p>12. My (<a href="http://davidbrycehoward.com/">blog</a> | <a href="http://twitter.com/daveh0ward">@daveh0ward</a>) contribution was a brief <a href="http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-26-dba-skillz/">discussion</a> of what I think experienced DBA&#8217;s provide to an organization.<br />
Original T-SQL Tuesday <a href="http://sqlskills.com/BLOGS/PAUL/post/Invitation-to-participate-in-T-SQL-Tuesday-12-e28093-Why-are-DBA-skills-necessary.aspx">12</a></p>
<p>13. Carlos Bossy (<a href="http://carlosbossy.wordpress.com/">blog</a> | <a href="http://twitter.com/carlosbossy">@carlosbossy</a>) covers a <a href="http://carlosbossy.wordpress.com/2012/01/10/tsql-tuesday-026-second-chances/">topic</a> I&#8217;m excited to learn more about:  the new windowing functions in SQL 2012, specifically in dealing with sliding aggregations.<br />
Original T-SQL Tuesday <a href="http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/come-one-come-all-to">16</a></p>
<p>14. Ricardo Leka (<a href="http://leka.com.br/">blog</a> | <a href="http://twitter.com/bigleka">@bigleka</a>) shares an <a href="http://leka.com.br/2012/01/10/t-sql-tuesday-26-segundas-chances/">improvement</a> to a previous SQLCMD script he wrote to allow for creating a database mirror in a more dynamic way.<br />
Original T-SQL Tuesday <a href="http://sqlblog.com/blogs/allen_white/archive/2011/12/05/t-sql-tuesday-025-invitation-to-share-your-tricks.aspx">25</a></p>
<p>Thanks again to everyone who contributed! See you next month.</p>
<img src="http://feeds.feedburner.com/~r/DavesSqlBlog/~4/XSVApZsMDqQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-026-the-wrap-up/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-026-the-wrap-up/</feedburner:origLink></item>
		<item>
		<title>T-SQL Tuesday #26 – DBA Skillz</title>
		<link>http://feedproxy.google.com/~r/DavesSqlBlog/~3/AlnPaD1ps6o/</link>
		<comments>http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-26-dba-skillz/#comments</comments>
		<pubDate>Tue, 10 Jan 2012 23:16:07 +0000</pubDate>
		<dc:creator>David Howard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbrycehoward.com/?p=427</guid>
		<description><![CDATA[Since I&#8217;m hosting T-SQL Tuesday this month, I really wanted to participate as well. I chose the topic I missed called Why are DBA Skills Necessary? This topic was originally hosted by Paul Randal (blog&#124;@PaulRandal) back in November of 2010. &#8230; <a href="http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-26-dba-skillz/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Since I&#8217;m hosting T-SQL Tuesday this <a href="http://davidbrycehoward.com/archive/2012/01/tsql-tuesday-026-second-chances/">month</a>, I really wanted to participate as well.  I chose the topic I missed called Why are DBA Skills Necessary? This topic was <a href="http://sqlskills.com/BLOGS/PAUL/post/Invitation-to-participate-in-T-SQL-Tuesday-12-e28093-Why-are-DBA-skills-necessary.aspx">originally</a> hosted by Paul Randal (<a href= "http://sqlskills.com/BLOGS/PAUL/">blog</a>|<a href="http://twitter.com/PaulRandal">@PaulRandal</a>) back in November of 2010.<a href="http://davidbrycehoward.com/archive/2012/01/tsql-tuesday-026-second-chances/"><img style="display: inline; float: right" align="right" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/tsqltuesday.gif" width="200" height="200"></a></p>
<p>This is an interesting topic for me because I&#8217;ve spent time on both sides of the fence, both as a developer and a DBA.  My current role is primarily as a production DBA with many mission critical SQL Servers in-house.   I&#8217;ve also worked in smaller companies that didn&#8217;t have a full-time DBA, but rather had multiple developers with some DBA experience.  My contention is that not every organization needs a DBA, but every organization that has critical databases needs someone with DBA skills.</p>
<p>Below, I attempted to quickly come up with a list of skills a DBA should bring to a company.  These are skills that companies need (to varying levels of degree) that experienced DBAs should have (again, to varying levels of degree).  I came up with off the top of my head, in no particular order:</p>
<ul>
<li>Designer of physical architecture.  Answers questions like how much memory do we need? What RAID level should we use?</li>
<li>Has knowledge of proper database design e.g. normalization, referential integrity</li>
<li>Protector of the data</li>
<li>Has knowledge of the business and how changes to the databases affect the business</li>
<li>Reviewer of code and schema reviews with database performance and manageability in mind</li>
<li>Acts as a layer of security to meet regulatory compliance and to avoid company exposure to liability</li>
<li>Expert in DR/HA, Backup/Restore strategy, meeting recovery time SLAs</li>
<li>Saver of money by getting the most out of the current hardware</li>
<li>Integrator of data between systems</li>
<li>Knows what is going on behind the scenes, internals</li>
<li>Learns constantly</li>
<li>Keeps up with changes to SQL Server and to trends in the industry</li>
<li>Supporter of users</li>
<li>Monitors proactively, responds to issues before they become problems or big problems</li>
<li>Trainer of junior DBAs and developers in doing things the right way</li>
<li>Enforcer of standards</li>
<li>Lastly, someone who knows what to do when everything goes wrong</li>
</ul>
<p>The world is all about data these days, data always seems to be the most important thing, and the amount of data is always <a href="http://www.computerworld.com/s/article/9217988/World_s_data_will_grow_by_50X_in_next_decade_IDC_study_predicts">growing</a>.  What would your company do if it lost its list of pending orders, or if the customer list fell into the wrong hands, or if the database goes corrupt and there are no good backups to revert to.  </p>
<p>Or any number of other things.  DBA skills are as important now as ever.</p>
<img src="http://feeds.feedburner.com/~r/DavesSqlBlog/~4/AlnPaD1ps6o" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-26-dba-skillz/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-26-dba-skillz/</feedburner:origLink></item>
		<item>
		<title>T-SQL Tuesday in Local Time</title>
		<link>http://feedproxy.google.com/~r/DavesSqlBlog/~3/G4D_R-HNT3c/</link>
		<comments>http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-in-local-time/#comments</comments>
		<pubDate>Thu, 05 Jan 2012 14:15:49 +0000</pubDate>
		<dc:creator>David Howard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbrycehoward.com/?p=388</guid>
		<description><![CDATA[The January edition of T-SQL Tuesday is next week! If you knew that, then you probably already know that the start and end times for T-SQL Tuesday are always at midnight UTC time, and that finding the current UTC date &#8230; <a href="http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-in-local-time/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The January edition of <a href="http://davidbrycehoward.com/archive/2012/01/tsql-tuesday-026-second-chances/">T-SQL Tuesday</a> is next week!  If you knew that, then you probably already know that the start and end times for T-SQL Tuesday are always at midnight UTC time, and that finding the current UTC date in SQL is as simple as using the GETUTCDATE() function.</p>
<pre class="brush: sql; title: ; notranslate">
SELECT GETUTCDATE();
</pre>
<p>You can obviously compare the two, but for any T-SQL Tuesday, the questions I really want answered are:  &#8220;When does it start (in local time)?&#8221; and &#8220;How much time do I have before it starts and until it ends?&#8221;<img style="background-image: none; border-right-width: 0px; margin: 0px 15px 0px 0px; padding-left: 5px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 5px" title="Get Moving!" border="0" alt="Get Moving!" align="left" src="http://davidbrycehoward.com/wp-content/uploads/2012/01/alarmclock.jpg" width="220" height="220">  The script below will answer those questions.  </p>
<p>This script runs for the current month, and assumes that T-SQL Tuesday is on the second Tuesday of the month (which it *usually* is).  And for obvious reasons, it will only work on SQL 2008 and later.</p>
<p>Just now, running it now on my machine gave the following output:</p>
<blockquote><p>Local time now: Jan  5 2012  8:09AM<br />
The start of T-SQL Tuesday for this month is Jan  9 2012  6:00PM and the end is Jan 10 2012  6:00PM local time.<br />
You have 4 days, 9 hours, 50 mins, and 53 seconds before it starts. Better get moving!</p></blockquote>
<pre class="brush: sql; title: ; notranslate">
DECLARE
	@Now DATETIMEOFFSET(0),
	@TZ INT,
	@FDOM DATETIMEOFFSET(0),
	@2ndTues DATETIMEOFFSET(0),
	@TuesStart AS DATETIMEOFFSET(0),
	@TuesEnd AS DATETIMEOFFSET(0),
	@Msg VARCHAR(MAX);

-- Save the current datetime and offset
SELECT @Now =
	SYSDATETIMEOFFSET(), @TZ = DATEPART(TZ,SYSDATETIMEOFFSET());

-- Get the first day of the current month (in UTC)
SET @FDOM =
	DATEADD(dd, DATEDIFF(dd, 0, DATEADD(DAY, -1 * (DATEPART(DAY,@Now) - 1), @Now)), 0) ;

-- Get the second Tuesday of the current month and start/end datetimes (in UTC)
SET @2ndTues =
	DATEADD(DAY, (7 + (10 - DATEPART(weekday,(DATEADD(DAY, 7, @FDOM)))) % 7), @FDOM);
SELECT @TuesStart = CAST(CAST(@2ndTues AS DATE) AS DATETIMEOFFSET(0)),
	@TuesEnd = CAST(CAST(DATEADD(day, 1, @2ndTues) AS DATE) AS DATETIMEOFFSET(0));

-- Display T-SQL Tuesday datetimes in local time
SET @Msg = 'Local time now: ' + CAST(CONVERT(DATETIME, @Now) AS VARCHAR);
PRINT @Msg;
SET @Msg = 'The start of T-SQL Tuesday for this month is '
	+ CAST(CONVERT(DATETIME, SWITCHOFFSET(@TuesStart, @TZ)) AS VARCHAR)
	+ ' and the end is ' + CAST(CONVERT(DATETIME, SWITCHOFFSET(@TuesEnd, @TZ)) AS VARCHAR)
	+ ' local time.';
PRINT @Msg;

-- Countdown stats
IF @Now &lt; @TuesStart
BEGIN
	SET @Msg = 'You have ' + CAST(DATEDIFF(day, @Now, @TuesStart)-1 AS VARCHAR) + ' days, '
		+ CAST((DATEDIFF(hour, @Now, @TuesStart) % 24)-1 AS VARCHAR) + ' hours, '
		+ CAST((DATEDIFF(minute, @Now, @TuesStart) % 60)-1 AS VARCHAR) + ' mins, and '
		+ CAST((DATEDIFF(second, @Now, @TuesStart) % 60) AS VARCHAR)
		+ ' seconds before it starts. Better get moving!';
	PRINT @Msg;
END
ELSE IF @Now &gt;= @TuesStart AND @Now &lt;= @TuesEnd
BEGIN
	SET @Msg = 'You have ' + CAST(DATEDIFF(day, @Now, @TuesEnd)-1 AS VARCHAR) + ' days, '
		+ CAST((DATEDIFF(hour, @Now, @TuesEnd) % 24)-1 AS VARCHAR) + ' hours, '
		+ CAST((DATEDIFF(minute, @Now, @TuesEnd) % 60)-1 AS VARCHAR) + ' mins, and '
		+ CAST((DATEDIFF(second, @Now, @TuesEnd) % 60) AS VARCHAR)
		+ ' seconds before T-SQL Tuesday ends. Publish!';
	PRINT @Msg;
END
ELSE IF @Now &gt; @TuesEnd
	PRINT 'T-SQL Tuesday is over for this month.  See you next month!';
</pre>
<p>Confession:  I really did this as an excuse to learn about some of the new date functionality in SQL 2008+ that I haven&#8217;t had a chance to use yet like DATETIMEOFFSET datatype and the SYSDATETIMEOFFSET() funciton, but hopefully it&#8217;s helpful as well.</p>
<p>Thanks, and remember, the clock is ticking!  </p>
<img src="http://feeds.feedburner.com/~r/DavesSqlBlog/~4/G4D_R-HNT3c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-in-local-time/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-in-local-time/</feedburner:origLink></item>
		<item>
		<title>TSQL Tuesday #026 – Second Chances</title>
		<link>http://feedproxy.google.com/~r/DavesSqlBlog/~3/olA1py3NDtY/</link>
		<comments>http://davidbrycehoward.com/archive/2012/01/tsql-tuesday-026-second-chances/#comments</comments>
		<pubDate>Tue, 03 Jan 2012 06:43:33 +0000</pubDate>
		<dc:creator>David Howard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbrycehoward.com/?p=352</guid>
		<description><![CDATA[UPDATE: The Wrap-Up is here. Happy New Year everyone! Welcome to 2012. Every new year brings with it a fresh start, a second chance to do things differently.&#160; In the spirit of second chances, for this month&#8217;s T-SQL Tuesday, please &#8230; <a href="http://davidbrycehoward.com/archive/2012/01/tsql-tuesday-026-second-chances/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>UPDATE: The Wrap-Up is <a href="http://davidbrycehoward.com/archive/2012/01/t-sql-tuesday-026-the-wrap-up/">here</a>.</p>
<p>Happy New Year everyone! Welcome to 2012.
<p align="left">Every new year brings with it a fresh start, a second chance to do things differently.&nbsp; In the spirit of second chances, for this month&#8217;s T-SQL Tuesday, please pick any one of the previous 25 T-SQL Tuesday topics and write about it. You can choose one of the topics you participated in before, or you can choose one you missed for some reason.&nbsp; <img style="display: inline; float: right" align="right" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/tsqltuesday.gif" width="200" height="200"></p>
<p>Maybe you were just too busy when Michael Swart invited everyone to write about <a href="http://michaeljswart.com/2010/09/invitation-to-participate-in-t-sql-tuesday-10-indexes/">indexes</a>. Or maybe you weren&#8217;t quite happy with the CTE post you came up with when Bob Pusateri <a href="http://www.bobpusateri.com/archive/2011/04/invitation-to-t-sql-tuesday-18-ctes/">hosted</a>.&nbsp; Or maybe you have a ton to say about IO, but like me, you didn’t know anything about T-SQL Tuesday until long after Mike Walsh’s <a href="http://www.straightpathsql.com/archives/2010/03/invitation-for-t-sql-tuesday-004-io/">month</a>.</p>
<p>Well now is your chance to set things straight!&nbsp; In fact, if you like, you can even throw down a few resolutions for the new year (see Jen McCown’s <a href="http://www.midnightdba.com/Jen/2011/01/t-sql-tuesday-resolutions/">#14</a>).&nbsp; And if this is your first T-SQL Tuesday, just pick a topic and jump in.
<p>As with any T-SQL Tuesday, the standard rules apply:
<ul>
<li>Your post must go live next Tuesday GMT (between 00:00:00 GMT on Tuesday January 10 and 00:00:00 GMT on Wednesday January 11).
<li>Your post should link back to this post, and you should leave a comment or a trackback here regarding your post.
<li>&#8220;T-SQL Tuesday #026&#8243; should be included in the title of the post.
<li>If you&#8217;re on Twitter, tweet about your post using the hash tag #TSQL2sDay</li>
</ul>
<p>Since this month is a bit unusual, here are a couple additional rules:
<ul>
<li>Your post should be new in content, in other words don&#8217;t just repost a previous T-SQL Tuesday entry (yours or anyone else’s <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://davidbrycehoward.com/wp-content/uploads/2012/01/wlEmoticon-smile.png">)</li>
<li>Somewhere in your post, you should say what T-SQL Tuesday topic name and/or number you chose to write about.</li>
</ul>
<p>I can&#8217;t wait to see which topics everyone chooses and the posts that come out of those.&nbsp; And of course after it’s done, I&#8217;ll summarize the posts on this blog within a couple of days.
<p>To refresh your memory, below is a history of all T-SQL Tuesday topics to date.&nbsp; It’s a pretty amazing list.
<ol>
<li><a href="http://sqlblog.com/blogs/adam_machanic/default.aspx">Adam Machanic</a> &#8211; <a href="http://sqlblog.com/blogs/adam_machanic/archive/2009/11/30/invitation-to-participate-in-t-sql-tuesday-001-date-time-tricks.aspx">Date/Time Tricks</a>
<li><a href="http://sqlblog.com/blogs/adam_machanic/default.aspx">Adam Machanic</a> &#8211; <a href="http://sqlblog.com/blogs/adam_machanic/archive/2010/01/04/invitation-for-t-sql-tuesday-002-a-puzzling-situation.aspx">A Puzzling Situation</a>
<li><a href="http://sqlblog.com/blogs/rob_farley/default.aspx">Rob Farley</a> – <a href="http://msmvps.com/blogs/robfarley/archive/2010/02/02/invitation-for-t-sql-tuesday-003-relationships.aspx">Relationships</a>
<li><a href="http://www.straightpathsql.com/blog/">Mike Walsh</a> &#8211; <a href="http://www.straightpathsql.com/archives/2010/03/invitation-for-t-sql-tuesday-004-io/">IO</a>
<li><a href="http://sqlvariant.com/wordpress/">Aaron Nelson</a> – <a href="http://sqlvariant.com/wordpress/index.php/2010/04/t-sql-tuesday-005-reporting/">Reporting</a></li>
<li><a href="http://sqlblog.com/blogs/michael_coles/default.aspx">Michael Coles</a> &#8211; <a href="http://sqlblog.com/blogs/michael_coles/archive/2010/05/03/t-sql-tuesday-006-what-about-blob.aspx">&#8220;What about BLOB?&#8221;</a> </li>
<li><a href="http://sqlchicken.com/">Jorge Segarra</a> &#8211; <a href="http://sqlchicken.com/2010/06/t-sql-tuesday-007-summertime-in-the-sql/">Summertime in the SQL</a></li>
<li><a href="http://www.sqlsoldier.com/wp/">Robert Davis</a> &#8211; <a href="http://www.sqlsoldier.com/wp/sqlserver/tsql-tuesday-008-tips-for-giving-a-good-interview-for-the-new-dba">Gettin&#8217; Schooled</a></li>
<li><a href="http://jasonbrimhall.info/">Jason Brimhall</a> &#8211; <a href="http://jasonbrimhall.info/2010/08/03/t-sql-tuesday-009-beach-time/">Beach Time</a> </li>
<li><a href="http://michaeljswart.com/">Michael Swart</a> – <a href="http://michaeljswart.com/2010/09/invitation-to-participate-in-t-sql-tuesday-10-indexes/">Indexes</a>
<li><a href="http://sankarreddy.com/">Sankar Reddy</a> &#8211; <a href="http://sankarreddy.com/2010/10/invitation-to-participate-in-t-sql-tuesday-11-misconceptions-in-sql-server/">Misconceptions in SQL Server</a>
<li><a href="http://sqlskills.com/BLOGS/PAUL/post/Invitation-to-participate-in-T-SQL-Tuesday-12-e28093-Why-are-DBA-skills-necessary.aspx">Paul Randal</a> &#8211; <a href="http://sqlskills.com/BLOGS/PAUL/post/Invitation-to-participate-in-T-SQL-Tuesday-12-e28093-Why-are-DBA-skills-necessary.aspx">Why are DBA skills necessary?</a>
<li><a href="http://www.sqlservercentral.com/blogs/steve_jones/">Steve Jones</a> &#8211; <a href="http://www.sqlservercentral.com/blogs/steve_jones/2010/12/07/t_2D00_sql-tuesday-_2300_13-_2D00_-what-the-business-says-is-not-what-the-business-wants/">What the Business Says is not What the Business Wants</a>
<li><a href="http://www.midnightdba.com/Jen/">Jen McCown</a> – <a href="http://www.midnightdba.com/Jen/2011/01/t-sql-tuesday-resolutions/">Resolutions</a>
<li><a href="http://sqlasylum.wordpress.com/">Pat Wright</a> &#8211; <a href="http://sqlasylum.wordpress.com/2011/02/01/invitation-to-t-sql-tuesday-15-automation-in-sql-server/">Automation in SQL Server</a>
<li><a href="http://blogs.lessthandot.com/index.php/All/?author=420">Jes Borland</a> – <a href="http://blogs.lessthandot.com/index.php/DataMgmt/DBProgramming/come-one-come-all-to">Aggregations</a>
<li><a href="http://mattvelic.com/">Matt Velic</a> &#8211; <a href="http://mattvelic.com/tsql-tuesday-17-invite/">Apply Knowledge</a>
<li><a href="http://www.bobpusateri.com/">Bob Pusateri</a> – <a href="http://www.bobpusateri.com/archive/2011/04/invitation-to-t-sql-tuesday-18-ctes/">CTEs</a>
<li><a href="http://www.allenkinsel.com/">Allen Kinsel</a> &#8211; <a href="http://www.allenkinsel.com/archive/2011/06/invitation-for-t-sql-tuesday-19-disasters-recovery/">Disasters &amp; Recovery</a>
<li><a href="http://troubleshootingsql.com/">Amit Banerjee</a> &#8211; <a href="http://troubleshootingsql.com/2011/07/05/invitation-for-t-sql-tuesday-19-t-sql-best-practices/">T-SQL Best Practices</a>
<li><a href="http://sqlblog.com/blogs/adam_machanic/default.aspx">Adam Machanic</a> &#8211; <a href="http://sqlblog.com/blogs/adam_machanic/archive/2011/08/03/t-sql-tuesday-21-a-day-late-and-totally-full-of-it.aspx">Inelegant Yet Educational</a>
<li><a href="http://www.sqlservercentral.com/blogs/pearlknows/">Robert Pearl</a> &#8211; <a href="http://www.sqlservercentral.com/blogs/pearlknows/2011/09/06/invitation-for-t-sql-tuesday-22-data-presentation/">Data Presentation</a>
<li><a href="http://codegumbo.com/">Stuart Ainsworth</a> – <a href="http://codegumbo.com/index.php/2011/09/27/tsql2sday-t-sql-tuesday-23early-edition/">Joins</a>
<li><a href="http://bradsruminations.blogspot.com/">Brad Schultz</a> &#8211; <a href="http://bradsruminations.blogspot.com/2011/10/invitation-for-t-sql-tuesday-024-prox-n.html">Prox ‘n’ Funx</a>
<li><a href="http://sqlblog.com/blogs/allen_white/default.aspx">Allen White</a> &#8211; <a href="http://sqlblog.com/blogs/allen_white/archive/2011/12/05/t-sql-tuesday-025-invitation-to-share-your-tricks.aspx">T-SQL Tricks</a></li>
</ol>
<p>Thanks in advance for participating!</p>
<img src="http://feeds.feedburner.com/~r/DavesSqlBlog/~4/olA1py3NDtY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://davidbrycehoward.com/archive/2012/01/tsql-tuesday-026-second-chances/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		<feedburner:origLink>http://davidbrycehoward.com/archive/2012/01/tsql-tuesday-026-second-chances/</feedburner:origLink></item>
		<item>
		<title>TOP Tricks (T-SQL Tuesday #25)</title>
		<link>http://feedproxy.google.com/~r/DavesSqlBlog/~3/z9Zf-vUeVi4/</link>
		<comments>http://davidbrycehoward.com/archive/2011/12/top-tricks-t-sql-tuesday-25/#comments</comments>
		<pubDate>Tue, 13 Dec 2011 15:29:34 +0000</pubDate>
		<dc:creator>David Howard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbrycehoward.com/?p=313</guid>
		<description><![CDATA[T-SQL Tuesday is here again, brought to us this month by Allen White (blog&#124;@SQLRunr). I’ve read Allen’s blog many times for PowerShell advice, but today he’s asking for your favorite T-SQL tricks. I&#8217;m not sure if this qualifies as a &#8230; <a href="http://davidbrycehoward.com/archive/2011/12/top-tricks-t-sql-tuesday-25/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>T-SQL Tuesday is here again, brought to us this month by Allen White (<a href="http://sqlblog.com/blogs/allen_white/default.aspx">blog</a>|<a href="https://twitter.com/#!/SQLRunr">@SQLRunr</a>).  I’ve read Allen’s blog many times for PowerShell advice, but today he’s asking for your favorite T-SQL tricks.<a title="T-SQL Tuesday" href="http://sqlblog.com/blogs/allen_white/archive/2011/12/05/t-sql-tuesday-025-invitation-to-share-your-tricks.aspx"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; float: right; padding-top: 0px; border: 0px;" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/tsqltuesday.gif" alt="" width="240" height="240" align="right" border="0" /></a></p>
<p>I&#8217;m not sure if this qualifies as a &#8220;trick&#8221; per se since it’s pretty simple and well documented.  But  it has come up several times in the past few weeks during code reviews, so I am sure that it’s something that not everyone is familiar with.</p>
<p>It seems like most T-SQL developers know that the TOP keyword can be used to SELECT the TOP n number of records.  I use it all the time when trying to get a quick look at the data, and SSMS has it as a built in menu option.</p>
<p>Selecting the first 100 records of a table is easy.</p>
<pre class="brush: sql; title: ; notranslate">
SELECT TOP 100 *
FROM Sales.Customer;
</pre>
<p>So what if you don&#8217;t want 100 records, but instead you want to dynamically specify the number of rows to be returned?  Often, developers will try to do something like this is a stored procedure:</p>
<pre class="brush: sql; title: ; notranslate">
DECLARE @NumRows int = 10;
SELECT TOP @NumRows * FROM Sales.Customer;
</pre>
<p>This results in an error:<span style="color: #ff0000;"><br />
Msg 102, Level 15, State 1, Line 2<br />
Incorrect syntax near &#8216;@NumRows&#8217;.</span></p>
<p>An accurate but not very helpful error message.  </p>
<p>From here, many developers will turn to dynamic SQL to solve the problem.  While dynamic SQL is perfectly appropriate in many situations, it&#8217;s not really needed here at all.  The sad part is that the developer was almost there with the first attempt, they were just missing one little thing &#8211; the parentheses.</p>
<pre class="brush: sql; title: ; notranslate">
DECLARE @NumRows int = 10;
SELECT TOP (@NumRows) * FROM Sales.Customer;
</pre>
<p>The TOP keyword can also be used with other DML statements such as INSERT, UPDATE and DELETE. In those cases the parentheses are required, even if you specify only a number. The parentheses should be there when you SELECT a TOP number as well, but they are not required for reasons of backwards compatibility and in my experience, no one uses them.  More info <a href="http://msdn.microsoft.com/en-us/library/ms189463.aspx">here</a>.</p>
<p>In fact, in Management Studio, when you right click on a table and choose SELECT TOP 1000 Rows…, the query SSMS produces has a TOP 1000 without parentheses.  And this is still true in SQL 2012 (at least in CTP 3).</p>
<p>One last note:  if the TOP amount used as an input parameter varies wildly, you may run into problems due to parameter sniffing.  A query with SELECT TOP 100000 records might look very different than a SELECT TOP 10, but the stored procedure will be compiled based on the first value passed in.  There are ways to <a href="http://davidbrycehoward.com/archive/2011/11/fixing-the-query-plan-for-a-stored-procedure-t-sql-tuesday-24/">work around that</a>, one of them being the full dynamic SQL solution.</p>
<p>Thanks for reading and happy Tuesday!</p>
<img src="http://feeds.feedburner.com/~r/DavesSqlBlog/~4/z9Zf-vUeVi4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://davidbrycehoward.com/archive/2011/12/top-tricks-t-sql-tuesday-25/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://davidbrycehoward.com/archive/2011/12/top-tricks-t-sql-tuesday-25/</feedburner:origLink></item>
		<item>
		<title>Fixing the Query Plan for a Stored Procedure (T-SQL Tuesday #24)</title>
		<link>http://feedproxy.google.com/~r/DavesSqlBlog/~3/4QTtxcjjUlk/</link>
		<comments>http://davidbrycehoward.com/archive/2011/11/fixing-the-query-plan-for-a-stored-procedure-t-sql-tuesday-24/#comments</comments>
		<pubDate>Wed, 09 Nov 2011 06:05:03 +0000</pubDate>
		<dc:creator>David Howard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbrycehoward.com/?p=300</guid>
		<description><![CDATA[It looks like T-SQL Tuesday is here again, brought to us this time by Brad Schultz (blog) on the topic of stored procedures and functions.  It&#8217;s been a while since I joined this blog party (or blogged at all for &#8230; <a href="http://davidbrycehoward.com/archive/2011/11/fixing-the-query-plan-for-a-stored-procedure-t-sql-tuesday-24/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>It looks like T-SQL Tuesday is here again, brought to us this time by Brad Schultz (<a href="http://bradsruminations.blogspot.com/">blog</a>) on the topic of stored procedures and functions.  It&#8217;s been a while since I joined this blog party (or blogged at all for that matter), but this topic jumped out at me, so here we go.<a title="T-SQL Tuesday" href="http://bradsruminations.blogspot.com/2011/10/invitation-for-t-sql-tuesday-024-prox-n.html"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; float: right; padding-top: 0px; border: 0px;" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/tsqltuesday.gif" alt="" width="240" height="240" align="right" border="0" /></a></p>
<p>I was lucky enough to attend the PASS conference in Seattle a few weeks ago.  A recurring theme in several of the sessions I attended was how to deal with bad query plans for stored procedures; or more specifically, how to deal with bad plans created as a result of parameter sniffing.  This topic had a direct impact on an issue I was dealing with at the time.</p>
<p>Here&#8217;s the scenario:</p>
<p>A particular stored procedure that runs very often and usually runs very fast, decides one day to start running much slower.  This causes elevated CPU on the server, and some timeouts in the application.  Manually updating statistics on tables that the procedure references fixes the problem temporarily, but it reoccurs the next day and again a few days later.</p>
<p>Digging in, we found that this stored procedure contains a single parameterized SELECT query.  The query is a combination of joins between several Product related tables, with the final join to a ProductCategory table on ProductID.  @CatID is an input parameter to the stored procedure, and is in the WHERE clause of the query.</p>
<p>Looking deeper, we found that most of the CatID values are in the ProductCategory table  100K or more times, but there are also some (new) CatIDs that are not in the ProductCategory at all.</p>
<p>When the procedure is recompiled, we found that the plan created is highly dependent on the value of the input parameter, namely @CatID.  There were two possibilities:</p>
<ol>
<li>The CatID passed in is one that exists in ProductCategory.<br />
&nbsp;<br />
In this case then the plan created was fine.   It contained a clustered index seek to ProductCategory using ProductID and CatID, then a nested loop join.</li>
<p>&nbsp;</p>
<li>The CatID passed in is one that does not exist in ProductCategory.<br />
&nbsp;<br />
Here, SQL created a plan which did a seek on a non-clustered index on ProductCategory(CatID) for that specific CatID with the estimated row count = 1.  That plan works fine if there are no (or very few) CatIDs in ProductCategory.  However, when there are 100K+ of them, it does 100K+ individual seeks followed by a lookup, which is very slow and very bad…</li>
</ol>
<p><span class="Apple-style-span" style="font-size: 16px; line-height: 24px;">It turned out that the optimizer was &#8220;sniffing&#8221; the value of CatID, and then using that sniffed value to optimize the plan.  So, how did we fix this?</span><br />
&nbsp;<br />
Before I reveal the solution we used, here are some of the potential solutions to the parameter sniffing problem I compiled from several PASS sessions, with the bulk coming from an excellent session by Gail Shaw (<a href="http://sqlinthewild.co.za/">blog</a>)).</p>
<ol>
<li>Break the stored procedure into multiple stored procedures (i.e., a separate one for each condition)</li>
<li>Rewrite using dynamic SQL with sp_executesql &#8211; this will create multiple query plans by condition.  Below are a couple of references for this solution from Erland Sommarskog (<a href="http://www.sommarskog.se/index.html">blog</a>)</li>
<ul>
<li><a href="http://www.sommarskog.se/dynamic_sql.html">The Curse and Blessings of Dynamic SQL</a></li>
<li><a href="http://www.sommarskog.se/dyn-search.html">Dynamic Search Conditions in T-SQL</a></li>
</ul>
<li>Assign the input parameters to local variables, and pass the local variables to the query (creates a “generic” plan, disables parameter sniffing and uses table statistics to do a best guess).</li>
<li>Add &#8220;option recompile&#8221; to the procedure (would be fine if the query is not executed frequently, otherwise may be too much overhead).</li>
<li>Add query hints (like “optimize for value” or “optimize for unknown”) and plan guides</li>
</ol>
<p>For our issue, we chose the third option, and assigned the input parameters to local variables.   This has the advantage of being a simple, relatively non-invasive change that could be implemented quickly.</p>
<p>Basically, we took the CatID input parameter and assigned it to a local variable defined in the stored procedure, then passed that local variable to the query.  This single level of indirection was enough to cause SQL to not use parameter sniffing, and to rather create a generic plan based on the statistics of the table.   The generic plan was the good plan described above, and which was exactly the plan we needed all the time.</p>
<p>I would be remiss if I neglected to mention that parameter sniffing is a good thing most of the time, and very often gives excellent results.  In cases where it causes problems though, it seems to cause big problems&#8230;</p>
<p>Thanks for reading, and happy Tuesday!</p>
<img src="http://feeds.feedburner.com/~r/DavesSqlBlog/~4/4QTtxcjjUlk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://davidbrycehoward.com/archive/2011/11/fixing-the-query-plan-for-a-stored-procedure-t-sql-tuesday-24/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://davidbrycehoward.com/archive/2011/11/fixing-the-query-plan-for-a-stored-procedure-t-sql-tuesday-24/</feedburner:origLink></item>
		<item>
		<title>More Recursion–Removing Multiple Spaces</title>
		<link>http://feedproxy.google.com/~r/DavesSqlBlog/~3/EbxyqzULlVA/</link>
		<comments>http://davidbrycehoward.com/archive/2011/05/more-recursionremoving-multiple-spaces/#comments</comments>
		<pubDate>Fri, 13 May 2011 13:10:08 +0000</pubDate>
		<dc:creator>David Howard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbrycehoward.com/?p=216</guid>
		<description><![CDATA[My last post about recursive CTEs reminded me of a recursive SQL Server function I wrote a while back for removing multiple spaces from strings.  By removing multiple spaces, I mean replacing all consecutive repeating spaces with a single space. &#8230; <a href="http://davidbrycehoward.com/archive/2011/05/more-recursionremoving-multiple-spaces/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>My last <a href="http://davidbrycehoward.com/archive/2011/05/the-missing-ungroup-by-clause/">post</a> about recursive CTEs reminded me of a recursive SQL Server function I wrote a while back for removing multiple spaces from strings.  By removing multiple spaces, I mean replacing all consecutive repeating spaces with a single space.</p>
<p><a href="http://davidbrycehoward.com/wp-content/uploads/2011/05/recursivedotspiral-thumb.jpg"><img class="size-medium wp-image-244 alignnone" title="Swirl" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/recursivedotspiral-thumb-300x187.jpg" alt="" width="300" height="200" align="right" /></a></p>
<p>This function was originally created as part of a cleansing process for incoming customer data, especially address related fields.  It worked very well, and I thought it performed well at the time, but as you&#8217;ll see, it was actually pretty slow compared to other options.</p>
<p>To solve this problem, the less experienced SQL developer might ask, why not just use the T-SQL REPLACE function? After all, the <a href=" http://msdn.microsoft.com/en-us/library/ms186862.aspx">REPLACE</a> function replaces all of the instances of once set of characters with another set of characters within a given string, right?</p>
<p>If you are only replacing double-spaces with single-spaces, a single REPLACE works just fine.  However, if there are longer sequences of spaces in the string, REPLACE doesn&#8217;t finish the job unless you apply it multiple times.  For example, a sequence of 4 spaces would be replaced with 2 single-spaces next to each other, which is a new double-space.  In order to remove all the the multiple spaces, REPLACE needs to be run multiple times, which is how the function below was born.</p>
<pre class="brush: sql; title: ; notranslate">
CREATE FUNCTION dbo.RemoveMultipleSpaces (@str NVARCHAR(MAX))
	RETURNS NVARCHAR(MAX)
AS
BEGIN
	IF CHARINDEX('  ', @str) = 0
		RETURN @str;

	RETURN dbo.RemoveMultipleSpaces(REPLACE(@str, '  ', ' '));
END
GO </pre>
<p>Here&#8217;s an example of calling REPLACE on an address string vs. calling the above function:</p>
<pre class="brush: sql; title: ; notranslate">
DECLARE @s VARCHAR(MAX) = '221B    BAKER       STREET';
SELECT REPLACE(RTRIM(@s), '  ', ' ') AS StillSpaced;
SELECT dbo.RemoveMultipleSpaces(@s) AS AllGood;
</pre>
<p>And the results:<br />
<a href="http://davidbrycehoward.com/wp-content/uploads/2011/05/spaces.jpg"><img class="alignnone size-full wp-image-231" title="spaces" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/spaces.jpg" alt="" width="179" height="88" /></a></p>
<p>An iterative version of this same function is straight-forward as well, though not quite as much fun to talk about&#8230;</p>
<pre class="brush: sql; title: ; notranslate">
CREATE FUNCTION dbo.RemoveMultipleSpacesItr(@str NVARCHAR(MAX))
	RETURNS NVARCHAR(MAX)
AS
BEGIN
	WHILE CHARINDEX('  ', @str) &gt; 0
		SET @str = REPLACE(@str, '  ', ' ');

	RETURN @str;
END
GO</pre>
<p>&nbsp;</p>
<p><strong>A Third Option</strong></p>
<p>Lastly, I ran across a very interesting <a href="http://www.sqlservercentral.com/articles/T-SQL/68378/">post</a> by <a href="http://www.sqlservercentral.com/Authors/Articles/Jeff_Moden/80567/">Jeff Moden</a> on SQL Server Central from a couple of months ago.  It describes a set based solution to this problem.  Basically, it involves a series of replaces, first with an &#8220;unlikely character&#8221; then with a single space.  Check it out the link for the details; a snippet of the code is below:</p>
<pre class="brush: sql; title: ; notranslate">
DECLARE @s VARCHAR(MAX) = '221B    BAKER       STREET';
SELECT REPLACE(
        REPLACE(
            REPLACE(
                LTRIM(RTRIM(@s))
            ,'  ',' '+CHAR(7))
        ,CHAR(7)+' ','')
    ,CHAR(7),'') AS CleanString ;
</pre>
<p><a href="http://davidbrycehoward.com/wp-content/uploads/2011/05/cleanstring.jpg"><img class="size-full wp-image-265 alignnone" title="cleanstring" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/cleanstring.jpg" alt="" width="164" height="42" /></a></p>
<p>That code can be used as is, or it could be put in a scalar or inline table valued function, like so:</p>
<pre class="brush: sql; title: ; notranslate">
CREATE FUNCTION dbo.RemoveMultipleSpaces3Scalar (@str NVARCHAR(MAX))
	RETURNS VARCHAR(MAX)
AS
BEGIN
	DECLARE @str1 VARCHAR(MAX);

	SELECT @str1 = REPLACE(
				REPLACE(
					REPLACE(
						LTRIM(RTRIM(@str))
					,'  ',' '+CHAR(7))
				,CHAR(7)+' ','')
			,CHAR(7),'') ;

	RETURN @str1;
END
GO

CREATE FUNCTION RemoveMultipleSpaces3TVF(@str NVARCHAR(MAX))
RETURNS TABLE
AS
  RETURN (
   SELECT REPLACE(
            REPLACE(
                REPLACE(
                    LTRIM(RTRIM(@str))
                ,'  ',' '+CHAR(7))
            ,CHAR(7)+' ','')
        ,CHAR(7),'') AS CleanString
  );
GO</pre>
<p>The scalar function would be called like the others, but the table valued function can be called by using a CROSS APPLY, for example:</p>
<pre class="brush: sql; title: ; notranslate">SELECT *
FROM Customer a
CROSS APPLY dbo.RemoveMultipleSpaces3TVF(a.Address1)
</pre>
<p>&nbsp;</p>
<p><strong>A Word About Performance</strong></p>
<p>Even though each of these pieces of code accomplishes the same task, the performance is very different.  To test, I took the address record we&#8217;ve been using (&#8217;221B &nbsp;&nbsp;&nbsp; BAKER &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; STREET&#8217;) and inserted it into a table 1,000,000 times.  Then I tested each of the functions by calling them against that table and inserting the results into a second table.  Each was run a few times to be sure there weren&#8217;t any delays due to warming the cache or compilation, etc.  The results are shown below (listed in the order discussed in this post):</p>
<p><a href="http://davidbrycehoward.com/wp-content/uploads/2011/05/performance2.jpg"><img  title="performance" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/performance2.jpg" alt="" /></a></p>
<p>Not too surprisingly, the non-set based solutions are the worst performers, with the recursive one bringing up the rear.  The set-based solution outside of a function, is smokin&#8217; fast relatively speaking &#8211; it&#8217;s not much slower than the control.</p>
<p>The performace difference looks like a lot, and it is, but that doesn&#8217;t always matter.  Like I mentioned earlier, in the customer data loading process I was working on, the recursive function was used and worked fine.  Looking back, that&#8217;s probably because the loads did many other things as well, so slower performance at this step wasn&#8217;t noticable in the big picture.  </p>
<p>If I were to repeat that project today though, I would take a hard look at the set based option.  Because every little bit counts.  </p>
<p>And because I&#8217;m a geek <img src='http://davidbrycehoward.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<img src="http://feeds.feedburner.com/~r/DavesSqlBlog/~4/EbxyqzULlVA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://davidbrycehoward.com/archive/2011/05/more-recursionremoving-multiple-spaces/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://davidbrycehoward.com/archive/2011/05/more-recursionremoving-multiple-spaces/</feedburner:origLink></item>
		<item>
		<title>The Missing UNGROUP BY Clause (T-SQL Tuesday #18)</title>
		<link>http://feedproxy.google.com/~r/DavesSqlBlog/~3/Vqla2tfYxWE/</link>
		<comments>http://davidbrycehoward.com/archive/2011/05/the-missing-ungroup-by-clause/#comments</comments>
		<pubDate>Tue, 10 May 2011 19:00:00 +0000</pubDate>
		<dc:creator>David Howard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbrycehoward.com/?p=182</guid>
		<description><![CDATA[For May 2011, T-SQL Tuesday is brought to us by Chicago&#8217;s own Bob Pusateri&#160; (blog &#124; @SQLBob). Bob chose common table expressions, otherwise know as CTEs as the topic of the month.&#160; Thanks for hosting Bob, and for the great &#8230; <a href="http://davidbrycehoward.com/archive/2011/05/the-missing-ungroup-by-clause/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>For May 2011, T-SQL Tuesday is brought to us by Chicago&#8217;s own Bob Pusateri&nbsp; (<a href="http://www.bobpusateri.com/">blog</a> | <a href="http://twitter.com/#!/sqlbob">@SQLBob</a>).  Bob chose common table expressions, otherwise know as CTEs as the topic of the month.&nbsp; Thanks for hosting Bob, and for the great choice of topics.</p>
<p><a href="http://www.bobpusateri.com/archive/2011/04/invitation-to-t-sql-tuesday-18-ctes/"><img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 10px; padding-left: 0px; padding-right: 0px; display: inline; float: right; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="tsqltuesday" border="0" alt="tsqltuesday" align="right" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/tsqltuesday.gif" width="240" height="240"></a></p>
<p>I&#8217;ve been a fan of common table expressions, or CTEs, ever since they were introduced in SQL Server 2005. Originally they took a little getting used to.&nbsp; In my opinion though, once you&#8217;ve used them for a while, they get easier and eventually feel more natural than using sub-queries in many cases.</p>
<p>One of the coolest thing about CTEs is that they allow for the use of recursion in SQL queries, something that wasn’t possible before CTEs entered the picture. When code is recursive, it simply means that the code can reference itself &#8211; and it can do so repeatedly to get a desired result.&nbsp; BOL has a decent description and example of recursive CTEs <a href="http://msdn.microsoft.com/en-us/library/ms186243.aspx">here</a>.</p>
<p>The following is an example taken from a real-world project using a recursive CTE to do what I&#8217;m calling a &#8220;UNGROUP BY&#8221; operation. I&#8217;m sure that sounds a little odd and probably requires some explanation.</p>
<p><strong>Picture this…</strong></p>
<p>We have two staging tables that are part of the load process for a Sales database. The ImportHeader table contains customer info, the ImportDetail table holds product info, and the two are joined together on a TicketNumber.&nbsp; This is a standard one-to-many relationship, so for each ImportHeader record, there can be multiple ImportDetail records representing the different products purchased by a customer on a given sales ticket.</p>
<p>The tricky part is there is also a Qty field on each ImportDetail record representing the quantity.&nbsp; If a customer purchases multiple instances of the <strong>same</strong> product, the Qty field is set to the quantity purchased, rather than adding another line to the detail.</p>
<p><a href="http://davidbrycehoward.com/wp-content/uploads/2011/05/recursive.jpg"><img style="background-image: none; border-right-width: 0px; margin: 0px 15px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="recursive" border="0" alt="recursive" align="left" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/recursive_thumb.jpg" width="240" height="222"></a></p>
<p>What makes that tricky is that the sales system is expecting exactly one line for each product purchased; it doesn’t know anything about a quantity field.&nbsp; So in effect, we need to &#8220;ungroup&#8221; the detail records where Qty &gt; 1.</p>
<p>Make sense? The example code is shown below.</p>
<p>First, let&#8217;s create the tables and populate with some sample data.</p>
<p>
<pre class="brush: sql; title: ; notranslate">CREATE TABLE dbo.ImportHeader
(
	ImportHeaderID INT PRIMARY KEY IDENTITY(1,1),
	TicketNumber VARCHAR(50),
	CustomerID INT,
	FName VARCHAR(50),
	LName VARCHAR(50),
	PostalCode VARCHAR(50)
);

CREATE TABLE dbo.ImportDetail
(
	ImportDetailID INT PRIMARY KEY IDENTITY(1,1),
	TicketNumber VARCHAR(50),
	BrandName VARCHAR(50),
	ModelNumber VARCHAR(50),
	Price NUMERIC(12,2),
	Qty INT
);

INSERT dbo.ImportHeader
(TicketNumber, CustomerID, FName, LName, PostalCode)
SELECT '1000', 112, 'Bob', 'Loblaw', '60654'
UNION ALL
SELECT '1001', 213, 'Carl', 'Weathers', '60654'
UNION ALL
SELECT '1002', 314, 'Steve', 'Holt', '60654'
;

INSERT dbo.ImportDetail
(TicketNumber, BrandName, ModelNumber, Price, Qty)
SELECT '1000', 'Sony', 'KDL1000', '1999.99', 3
UNION ALL
SELECT '1001', 'Sanyo', 'KDL1005', '1799.99', 1
UNION ALL
SELECT '1002', 'Sanyo', 'KDL1005', '1799.99', 2
UNION ALL
SELECT '1002', 'Samsung', 'KDL1011', '1699.99', 1
;
</pre>
</p>
<p>Three customers were added with 3 different ticket numbers.&nbsp; The customers purchased 4 products, with varying quantities of each.&nbsp; </p>
<p>Now we can run a query to ungroup the data using a recursive CTE.</p>
<p>
<pre class="brush: sql; title: ; notranslate">WITH Products AS
(
SELECT
	TicketNumber, BrandName, ModelNumber, Price, Qty, 1 AS n
FROM dbo.ImportDetail
WHERE (Qty &gt; 0)
UNION ALL
SELECT
	TicketNumber, BrandName, ModelNumber, Price, Qty, n + 1
FROM Products
WHERE (Qty &gt; n)
)
SELECT
	ROW_NUMBER() OVER(ORDER BY a.TicketNumber, b.n) as RowNum,
	a.TicketNumber, a.CustomerID, a.FName, a.LName, a.PostalCode,
	b.BrandName, b.ModelNumber, b.Price, b.n
FROM dbo.ImportHeader a
JOIN Products b
	ON a.TicketNumber = b.TicketNumber
ORDER BY RowNum
;
</pre>
</p>
<p>The recursive portion of the query works like this:&nbsp; it includes all of the detail records at the first level (Qty &gt; 0), then unions that with the detail records where Qty &gt; 1, then unions that with the detail records where Qty &gt; 2, etc.&nbsp; This continues until there are no records left where Qty &gt; n.</p>
<p>As you can see in the output below, each line represents a single product purchased by a customer.&nbsp; The records have been successfully ungrouped.</p>
<p><a href="http://davidbrycehoward.com/wp-content/uploads/2011/05/CTE_Results.jpg"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="CTE_Results" border="0" alt="CTE_Results" src="http://davidbrycehoward.com/wp-content/uploads/2011/05/CTE_Results_thumb.jpg" width="640" height="149"></a></p>
<p>Recursive code is often described as elegant in its simplicity. If you were to compare this query to an iterative solution for the same task (which I didn’t write but try to imagine), you would probably agree.</p>
<p><strong>Recursion Limit</strong></p>
<p>One thing to keep in mind is that SQL Server puts a limit on the number of recursions that can happen.  This is done as a safety measure; and by default, SQL sets this limit to 100. If you were change the Qty for the first detail record from 3 to say, 142, you&#8217;ll get a nice error message like this:</p>
<p><font color="#ff0000">Msg 530, Level 16, State 1, Line 45<br />The statement terminated. The maximum recursion 100 has been exhausted before statement completion.</font></p>
<p>The value for the recursion limit can be changed using a query hint like so:&nbsp; <br />OPTION (MAXRECURSION 500), which would (obviously) change the limit to 500 levels.</p>
<p>Using OPTION (MAXRECURSION 0) removes the limit.&nbsp; This can be dangerous if a coding error causes you to end up with a circular reference.&nbsp; It’s always better to throw an error than to go into an infinite loop.</p>
<p>
Thanks for reading, and happy Tuesday!</p>
<img src="http://feeds.feedburner.com/~r/DavesSqlBlog/~4/Vqla2tfYxWE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://davidbrycehoward.com/archive/2011/05/the-missing-ungroup-by-clause/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://davidbrycehoward.com/archive/2011/05/the-missing-ungroup-by-clause/</feedburner:origLink></item>
		<item>
		<title>Meme Monday–Running with SQL</title>
		<link>http://feedproxy.google.com/~r/DavesSqlBlog/~3/6wTKontSLdM/</link>
		<comments>http://davidbrycehoward.com/archive/2011/04/meme-mondayrunning-with-sql/#comments</comments>
		<pubDate>Mon, 04 Apr 2011 13:43:52 +0000</pubDate>
		<dc:creator>David Howard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbrycehoward.com/?p=170</guid>
		<description><![CDATA[My Meme Monday 11 word blog post: &#8220;Running fast, heart racing, working through SQL problems in my mind.&#8221; I was on vacation last week in Arizona. We were in Phoenix a lot, but also spent time in Sedona and visited &#8230; <a href="http://davidbrycehoward.com/archive/2011/04/meme-mondayrunning-with-sql/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>My Meme Monday 11 word blog post:
<p>&#8220;Running fast, heart racing, working through SQL problems in my mind.&#8221;
<p>I was on vacation last week in Arizona. We were in Phoenix a lot, but also spent time in Sedona and visited the Grand Canyon. It was really beautiful there and very nice to be able to get away with the family to someplace warm and remote.
<p>With some free time, I was also able to get out for run almost every day. I love to run, and I&#8217;m just starting to get back into it after some time off. My history as a runner is kind of sporadic. I ran a lot during and after college, then got injured and stopped for a few years. Then in 2009 I trained for and ran (and finished!) the Chicago Marathon, which was an incredibly awesome experience. Since then I&#8217;ve run very little, at least up until the last few weeks.
<p>One of the things I love about running is chance to be alone with my thoughts for a short period of time. During those runs in AZ, I found myself thinking of many things, some related to database work. Those thoughts somehow evolved into thinking how much running is like working with SQL Server.&nbsp; Here&#8217;s a few I remember…
<ul>
<li>Both are fun, challenging and rewarding</li>
<li>They require practice and persistence</li>
<li>The more you give to either, the more you get out
<li>Can do it alone, but is better when you do it with other people</li>
</ul>
<p>Given those and other similarities, it&#8217;s not surprising to me that there are several runners in the SQL community. Since this is far beyond 11 words, I&#8217;m going to finish here by tagging 3 SQL folks that I know like to run: <a href="http://gillrowley.com/">Gill</a>, <a href="http://kmescha.wordpress.com/">Keith</a>, <a href="http://www.erinstellato.com/">Erin</a>.
<p>Happy Monday everyone!
<p>Thanks <a href="http://thomaslarock.com/">Tom</a> for the <a href="http://thomaslarock.com/2011/04/welcome-to-meme-monday/">idea</a>, and <a href="http://noelmckinney.com/">Noel</a> for tagging me.</p>
<img src="http://feeds.feedburner.com/~r/DavesSqlBlog/~4/6wTKontSLdM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://davidbrycehoward.com/archive/2011/04/meme-mondayrunning-with-sql/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://davidbrycehoward.com/archive/2011/04/meme-mondayrunning-with-sql/</feedburner:origLink></item>
		<item>
		<title>Disable all SQL Agent Jobs</title>
		<link>http://feedproxy.google.com/~r/DavesSqlBlog/~3/UJcN6VObfKk/</link>
		<comments>http://davidbrycehoward.com/archive/2011/03/disable-all-sql-agent-jobs/#comments</comments>
		<pubDate>Thu, 03 Mar 2011 14:00:18 +0000</pubDate>
		<dc:creator>David Howard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://davidbrycehoward.com/?p=146</guid>
		<description><![CDATA[Recently, I was looking for an easy way to disable all of the SQL Server Agent jobs as part of a migration to a new environment. My first thought was to just stop the SQL Agent service, but there were &#8230; <a href="http://davidbrycehoward.com/archive/2011/03/disable-all-sql-agent-jobs/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Recently, I was looking for an easy way to disable all of the SQL Server Agent jobs as part of a migration to a new environment. <a href="http://www.flickr.com/photos/zigazou76/4208935163/"><img style="background-image: none; padding-left: 10px; padding-right: 0px; display: inline; float: right; padding-top: 10px; border: 0px;" src="http://davidbrycehoward.com/wp-content/uploads/2011/03/stop-300x201.jpg" alt="" title="Stop it" width="210" height="140" /></a>My first thought was to just stop the SQL Agent service, but there were some jobs that were going to be used during the migration, so that was out.</p>
<p>Not wanting to reinvent the wheel, I ran a quick search to see if anyone had posted an example of this before.  I did find some results, but everything I found either used a cursor or updated system tables directly.  A cursor would be fine for this task performance-wise, but I hate using cursors if I don’t need to, and here you really don’t need to.</p>
<p>Here’s the simple script I came up with:</p>
<pre class="brush: sql; title: ; notranslate">declare @sql nvarchar(max) = '';
select
@sql += N'exec msdb.dbo.sp_update_job @job_name = ''' + name + N''', @enabled = 0;
' from msdb.dbo.sysjobs
where enabled = 1
order by name;

print @sql;
exec (@sql);
</pre>
<p>&nbsp;<br />
This queries the sysjobs table creates an exec statement of sp_update_job for each active job, then runs the batch.</p>
<pre class="brush: sql; title: ; notranslate">exec msdb.dbo.sp_update_job @job_name = 'SQLAgentJob1', @enabled = 0;
exec msdb.dbo.sp_update_job @job_name = 'SQLAgentJob2', @enabled = 0;
exec msdb.dbo.sp_update_job @job_name = 'SQLAgentJob3', @enabled = 0;
…
</pre>
<p>&nbsp;<br />
You can use the same technique to avoid cursors in other situations – I’ll blog about that another time.</p>
<img src="http://feeds.feedburner.com/~r/DavesSqlBlog/~4/UJcN6VObfKk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://davidbrycehoward.com/archive/2011/03/disable-all-sql-agent-jobs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://davidbrycehoward.com/archive/2011/03/disable-all-sql-agent-jobs/</feedburner:origLink></item>
	</channel>
</rss>

