<feed xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US">
    <title>TRUNCATE TABLE master..sysdatabases</title>
    <link rel="self" type="application/atom+xml" href="http://weblogs.sqlteam.com/robv/Atom.aspx" />
    <subtitle type="html">...and other neat SQL Server tricks</subtitle>
    <id>http://weblogs.sqlteam.com/robv/Default.aspx</id>
    <author>
        <name>Most Valuable Yak (Rob Volk)</name>
        <uri>http://weblogs.sqlteam.com/robv/Default.aspx</uri>
    </author>
    <generator uri="http://subtextproject.com" version="Subtext Version 2.5.1.0">Subtext</generator>
    <updated>2012-01-25T13:30:34Z</updated>
    <entry>
        <title>T-SQL Tuesday #025 &amp;ndash; CHECK Constraint Tricks</title>
        <link rel="alternate" type="text/html" href="http://weblogs.sqlteam.com/robv/archive/2011/12/13/t-sql-tuesday-025-ndash-check-constraint-tricks.aspx" />
        <id>http://weblogs.sqlteam.com/robv/archive/2011/12/13/t-sql-tuesday-025-ndash-check-constraint-tricks.aspx</id>
        <published>2011-12-13T14:24:28Z</published>
        <updated>2011-12-13T14:25:55Z</updated>
        <content type="html">&lt;p&gt;&lt;a target="_blank" href="http://sqlblog.com/blogs/allen_white/archive/2011/12/05/t-sql-tuesday-025-invitation-to-share-your-tricks.aspx"&gt;&lt;img style="FLOAT: left" alt="" src="http://www.upsearch.com/components/com_wordpress/wp/wp-content/uploads/2011/12/tsqltuesday.jpg" /&gt;&lt;/a&gt;Allen White (&lt;a target="_blank" href="http://sqlblog.com/blogs/allen_white/default.aspx"&gt;blog&lt;/a&gt; | &lt;a target="_blank" href="https://twitter.com/#!/SQLRunr"&gt;twitter&lt;/a&gt;), marathoner, SQL Server MVP and presenter, and all-around &lt;a title="MVP Deep Dives, Chapter 27" target="_blank" href="http://www.amazon.com/SQL-Server-MVP-Deep-Dives/dp/1935182048/ref=pd_sim_b_1"&gt;awesome author&lt;/a&gt; is hosting this month's &lt;a target="_blank" href="http://sqlblog.com/blogs/allen_white/archive/2011/12/05/t-sql-tuesday-025-invitation-to-share-your-tricks.aspx"&gt;T-SQL Tuesday on sharing SQL Server Tips and Tricks&lt;/a&gt;.  And for those of you who have attended my &lt;em&gt;Revenge: The SQL&lt;/em&gt; presentation, you know that I have 1 or 2 of them.  You'll also know that I don't recommend using anything I talk about in a production system, and will continue that advice here…although you might be sorely tempted.  Suffice it to say I'm not using these examples myself, but I think they're worth sharing anyway.&lt;/p&gt;
&lt;p&gt;Some of you have seen or read about &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ms189862.aspx"&gt;SQL Server constraints&lt;/a&gt; and have &lt;a title="Yeah Matt! Matt uses constraints! If you're a vendor, hire this guy!" target="_blank" href="http://mattvelic.com/tsql-tuesday-25/"&gt;applied them to your table designs&lt;/a&gt;…unless you're a vendor ;)…and may even use CHECK constraints to limit numeric values, or length of strings, allowable characters and such.  CHECK constraints can, however, do more than that, and can even provide enhanced security and other restrictions.&lt;/p&gt;
&lt;p&gt;One tip or trick that I didn't cover very well in the presentation is using constraints to do unusual things; specifically, limiting or preventing inserts into tables.  The idea was to use a CHECK constraint in a way that didn't depend on the actual data:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: green"&gt;-- create a table that cannot accept data
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;dbo&lt;span style="COLOR: gray"&gt;.&lt;/span&gt;JustTryIt&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;a &lt;span style="COLOR: blue"&gt;BIT &lt;/span&gt;&lt;span style="COLOR: gray"&gt;NOT NULL &lt;/span&gt;&lt;span style="COLOR: blue"&gt;PRIMARY KEY&lt;/span&gt;&lt;span style="COLOR: gray"&gt;,
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;chk_no_insert &lt;span style="COLOR: blue"&gt;CHECK &lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;GETDATE&lt;/span&gt;&lt;span style="COLOR: gray"&gt;()=&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;GETDATE&lt;/span&gt;&lt;span style="COLOR: gray"&gt;()+&lt;/span&gt;1&lt;span style="COLOR: gray"&gt;))

&lt;/span&gt;&lt;span style="COLOR: blue"&gt;INSERT &lt;/span&gt;dbo&lt;span style="COLOR: gray"&gt;.&lt;/span&gt;JustTryIt &lt;span style="COLOR: blue"&gt;VALUES&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;1&lt;span style="COLOR: gray"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;I'll let you run that yourself, but I'm sure you'll see that this is a pretty stupid table to have, since the CHECK condition will always be false, and therefore will prevent any data from ever being inserted.  I can't remember why I used this example but it was for some vague and esoteric purpose that applies to about, maybe, zero people.  I come up with a lot of examples like that.&lt;/p&gt;
&lt;p&gt;However, if you realize that these CHECKs are not limited to column references, and if you explore the &lt;a target="_blank" href="http://msdn.microsoft.com/en-us/library/ms174318.aspx"&gt;SQL Server function list&lt;/a&gt;, you could come up with a few that might be useful.  I'll let the names describe what they do instead of explaining them all:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;NoSA&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;a &lt;span style="COLOR: blue"&gt;int &lt;/span&gt;&lt;span style="COLOR: gray"&gt;not null, 
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;CHK_No_sa &lt;span style="COLOR: blue"&gt;CHECK &lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;SUSER_SNAME&lt;/span&gt;&lt;span style="COLOR: gray"&gt;()&amp;lt;&amp;gt;&lt;/span&gt;&lt;span style="COLOR: red"&gt;'sa'&lt;/span&gt;&lt;span style="COLOR: gray"&gt;))

&lt;/span&gt;&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;NoSysAdmin&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;a &lt;span style="COLOR: blue"&gt;int &lt;/span&gt;&lt;span style="COLOR: gray"&gt;not null, 
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;CHK_No_sysadmin &lt;span style="COLOR: blue"&gt;CHECK &lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;IS_SRVROLEMEMBER&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: red"&gt;'sysadmin'&lt;/span&gt;&lt;span style="COLOR: gray"&gt;)=&lt;/span&gt;0&lt;span style="COLOR: gray"&gt;))

&lt;/span&gt;&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;NoAdHoc&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;a &lt;span style="COLOR: blue"&gt;int &lt;/span&gt;&lt;span style="COLOR: gray"&gt;not null, 
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;CHK_No_AdHoc &lt;span style="COLOR: blue"&gt;CHECK &lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;OBJECT_NAME&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;@@PROCID&lt;/span&gt;&lt;span style="COLOR: gray"&gt;) IS NOT NULL))

&lt;/span&gt;&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;NoAdHoc2&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;a &lt;span style="COLOR: blue"&gt;int &lt;/span&gt;&lt;span style="COLOR: gray"&gt;not null, 
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;CHK_No_AdHoc2 &lt;span style="COLOR: blue"&gt;CHECK &lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;@@NESTLEVEL&lt;/span&gt;&lt;span style="COLOR: gray"&gt;&amp;gt;&lt;/span&gt;0&lt;span style="COLOR: gray"&gt;))

&lt;/span&gt;&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;NoCursors&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;a &lt;span style="COLOR: blue"&gt;int &lt;/span&gt;&lt;span style="COLOR: gray"&gt;not null, 
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;CHK_No_Cursors &lt;span style="COLOR: blue"&gt;CHECK &lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;@@CURSOR_ROWS&lt;/span&gt;&lt;span style="COLOR: gray"&gt;=&lt;/span&gt;0&lt;span style="COLOR: gray"&gt;))

&lt;/span&gt;&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;ANSI_PADDING_ON&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;a &lt;span style="COLOR: blue"&gt;int &lt;/span&gt;&lt;span style="COLOR: gray"&gt;not null, 
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;CHK_ANSI_PADDING_ON &lt;span style="COLOR: blue"&gt;CHECK &lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;@@OPTIONS &lt;/span&gt;&lt;span style="COLOR: gray"&gt;&amp;amp; &lt;/span&gt;16&lt;span style="COLOR: gray"&gt;=&lt;/span&gt;16&lt;span style="COLOR: gray"&gt;))

&lt;/span&gt;&lt;span style="COLOR: blue"&gt;CREATE TABLE &lt;/span&gt;TimeOfDay&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;a &lt;span style="COLOR: blue"&gt;int &lt;/span&gt;&lt;span style="COLOR: gray"&gt;not null, 
    &lt;/span&gt;&lt;span style="COLOR: blue"&gt;CONSTRAINT &lt;/span&gt;CHK_TimeOfDay &lt;span style="COLOR: blue"&gt;CHECK &lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&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: blue"&gt;hour&lt;/span&gt;&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;GETDATE&lt;/span&gt;&lt;span style="COLOR: gray"&gt;()) BETWEEN &lt;/span&gt;0 &lt;span style="COLOR: gray"&gt;AND &lt;/span&gt;1&lt;span style="COLOR: gray"&gt;))
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;GO

&lt;/span&gt;&lt;span style="COLOR: green"&gt;-- log in as sa or a sysadmin server role member, and try this:
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;INSERT &lt;/span&gt;NoSA &lt;span style="COLOR: blue"&gt;VALUES&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;1&lt;span style="COLOR: gray"&gt;)
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;INSERT &lt;/span&gt;NoSysAdmin &lt;span style="COLOR: blue"&gt;VALUES&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;1&lt;span style="COLOR: gray"&gt;)
&lt;/span&gt;&lt;span style="COLOR: green"&gt;-- note the difference when using sa vs. non-sa
-- then try it again with a non-sysadmin login

-- see if this works:
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;INSERT &lt;/span&gt;NoAdHoc &lt;span style="COLOR: blue"&gt;VALUES&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;1&lt;span style="COLOR: gray"&gt;)
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;INSERT &lt;/span&gt;NoAdHoc2 &lt;span style="COLOR: blue"&gt;VALUES&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;1&lt;span style="COLOR: gray"&gt;)
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;GO

&lt;/span&gt;&lt;span style="COLOR: green"&gt;-- then try this:
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;CREATE PROCEDURE &lt;/span&gt;NotAdHoc @val1 &lt;span style="COLOR: blue"&gt;int&lt;/span&gt;&lt;span style="COLOR: gray"&gt;, &lt;/span&gt;@val2 &lt;span style="COLOR: blue"&gt;int AS
SET NOCOUNT ON&lt;/span&gt;&lt;span style="COLOR: gray"&gt;;
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;INSERT &lt;/span&gt;NoAdHoc &lt;span style="COLOR: blue"&gt;VALUES&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;@val1&lt;span style="COLOR: gray"&gt;)
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;INSERT &lt;/span&gt;NoAdHoc2 &lt;span style="COLOR: blue"&gt;VALUES&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;@val2&lt;span style="COLOR: gray"&gt;)
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;GO

EXEC &lt;/span&gt;NotAdHoc 2&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;2

&lt;span style="COLOR: green"&gt;-- which values got inserted?
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;SELECT &lt;/span&gt;&lt;span style="COLOR: gray"&gt;* &lt;/span&gt;&lt;span style="COLOR: blue"&gt;FROM &lt;/span&gt;NoAdHoc
&lt;span style="COLOR: blue"&gt;SELECT &lt;/span&gt;&lt;span style="COLOR: gray"&gt;* &lt;/span&gt;&lt;span style="COLOR: blue"&gt;FROM &lt;/span&gt;NoAdHoc2&lt;/pre&gt;
&lt;pre class="code"&gt; &lt;/pre&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: green" /&gt;&lt;/pre&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: green"&gt;-- and this one just makes me happy :)
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;INSERT &lt;/span&gt;NoCursors &lt;span style="COLOR: blue"&gt;VALUES&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;1&lt;span style="COLOR: gray"&gt;)
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;DECLARE &lt;/span&gt;curs &lt;span style="COLOR: blue"&gt;CURSOR FOR SELECT &lt;/span&gt;1
&lt;span style="COLOR: blue"&gt;OPEN &lt;/span&gt;curs
&lt;span style="COLOR: blue"&gt;INSERT &lt;/span&gt;NoCursors &lt;span style="COLOR: blue"&gt;VALUES&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;2&lt;span style="COLOR: gray"&gt;)
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;CLOSE &lt;/span&gt;curs
&lt;span style="COLOR: blue"&gt;DEALLOCATE &lt;/span&gt;curs
&lt;span style="COLOR: blue"&gt;INSERT &lt;/span&gt;NoCursors &lt;span style="COLOR: blue"&gt;VALUES&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;3&lt;span style="COLOR: gray"&gt;)

&lt;/span&gt;&lt;span style="COLOR: blue"&gt;SELECT &lt;/span&gt;&lt;span style="COLOR: gray"&gt;* &lt;/span&gt;&lt;span style="COLOR: blue"&gt;FROM &lt;/span&gt;NoCursors&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;I'll leave the ANSI_PADDING_ON and TimeOfDay tables for you to test on your own, I think you get the idea.  (Also take a look at the NoCursors example, notice anything interesting?)  &lt;/p&gt;
&lt;p&gt;The real eye-opener, for me anyway, is the ability to limit bad coding practices like cursors, ad-hoc SQL, and sa use/abuse by using declarative SQL objects.  I'm sure you can see how and why this would come up when discussing &lt;em&gt;Revenge: The SQL.&lt;/em&gt;;) And the best part IMHO is that these work on pretty much any version of SQL Server, without needing Policy Based Management, DDL/login triggers, or similar tools to enforce best practices.&lt;/p&gt;
&lt;p&gt;All seriousness aside, I highly recommend that you spend some time letting your mind go wild with the possibilities and see how far you can take things.  There are no rules!&lt;/p&gt;
&lt;p&gt;(Hmmmm, what can I do with &lt;a title="Still works in SQL 2012!" target="_blank" href="http://msdn.microsoft.com/en-us/library/ms188064.aspx"&gt;rules&lt;/a&gt;?)&lt;/p&gt;
&lt;p&gt;#TSQL2sDay&lt;/p&gt;&lt;img src="/robv/aggbug/61393.aspx" width="1" height="1" /&gt;</content>
    </entry>
    <entry>
        <title>Queerie Memoree Spils</title>
        <link rel="alternate" type="text/html" href="http://weblogs.sqlteam.com/robv/archive/2011/10/19/queerie-memoree-spils.aspx" />
        <id>http://weblogs.sqlteam.com/robv/archive/2011/10/19/queerie-memoree-spils.aspx</id>
        <published>2011-10-18T17:24:04Z</published>
        <updated>2011-10-18T17:25:52Z</updated>
        <content type="html">&lt;p&gt;Did you know that if you run a query in SQL Server, and it processes it as a hash match, and there's not enough memory to fully process it, the memory will spill to disk?  You can find out all about it &lt;a title="Nope, not gonna link to that *OTHER* article.  I might get #sqlsue-d." href="http://msdn.microsoft.com/en-us/library/ms190736.aspx" target="_blank"&gt;here.&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Note: I know this makes even less sense than my usual blog posts do, so for more information, check out &lt;a href="https://twitter.com/#!/MidnightDBA" target="_blank"&gt;Jen's&lt;/a&gt; &lt;a href="http://www.midnightdba.com/Jen/" target="_blank"&gt;Awesomesauce&lt;/a&gt; &lt;a href="http://www.midnightdba.com/Jen/2011/10/rat-sues-corn-rather-rat-accuses-corn-of-thought-theft-or-something/" target="_blank"&gt;blog entry&lt;/a&gt; about it.  (Please don't sue me Jen!)&lt;/p&gt;  &lt;p&gt;#sqlsue&lt;/p&gt;&lt;img src="/robv/aggbug/61380.aspx" width="1" height="1" /&gt;</content>
    </entry>
    <entry>
        <title>SQL Saturday #89 in Atlanta!</title>
        <link rel="alternate" type="text/html" href="http://weblogs.sqlteam.com/robv/archive/2011/09/13/sql-saturday-89-in-atlanta.aspx" />
        <id>http://weblogs.sqlteam.com/robv/archive/2011/09/13/sql-saturday-89-in-atlanta.aspx</id>
        <published>2011-09-13T10:39:43Z</published>
        <updated>2011-09-13T11:00:52Z</updated>
        <content type="html">&lt;p&gt;(Yeah yeah, &lt;a target="_blank" href="http://www.sqlsaturday.com/89/location.aspx"&gt;technically it's in Alpharetta&lt;/a&gt;, but it's close enough.)&lt;/p&gt;
&lt;p&gt;&lt;font size="6"&gt;Saturday&lt;/font&gt;…&lt;font size="5"&gt;Saturday&lt;/font&gt;….Saturday…. &lt;font size="5"&gt;September 17th&lt;/font&gt;.  &lt;font size="5"&gt;&lt;strong&gt;TWO THOUSAND ELEVEN!&lt;/strong&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;OK, it's not a tractor pull, but it's even better:  FREE SQL SERVER TRAINING!  They have a &lt;a target="_blank" href="http://www.sqlsaturday.com/89/schedule.aspx"&gt;bunch of great speakers&lt;/a&gt; lined up, and for some reason, me.  (Protip: be good friends with &lt;a target="_blank" href="http://timradney.com/"&gt;the&lt;/a&gt; &lt;a title="Sweet &amp;amp; Ruthless" target="_blank" href="http://datachix.com/"&gt;program&lt;/a&gt; &lt;a target="_blank" href="http://sqlvariant.com/wordpress/"&gt;committee&lt;/a&gt;, have sufficient bribe funds, and if all else fails, lots of alcohol, drugs and a camera.  Ba-ZING!  You too can speak at SQL Saturday!)&lt;/p&gt;
&lt;p&gt;I will be presenting &lt;a title="It's a kid-friendly kind of revenge, no Sith involved" target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=89&amp;amp;sessionid=4667"&gt;Revenge: The SQL!&lt;/a&gt; in a new and improved SQL Saturday themed presentation.  Actually, it's the same ol' presentation, I just updated the slide theme to match the new &lt;a title="What is it?  It's....It's....it's green." target="_blank" href="http://www.sqlsaturday.com/"&gt;SQL Saturday website&lt;/a&gt; design.  (Yeah guys, thanks for changing that a month ago.  So much for coasting on the old format.) &lt;img style="BORDER-BOTTOM-STYLE: none; BORDER-LEFT-STYLE: none; BORDER-TOP-STYLE: none; BORDER-RIGHT-STYLE: none" class="wlEmoticon wlEmoticon-winkingsmile" alt="Winking smile" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/robv/Windows-Live-Writer/SQL-Saturday-89-in-Atlanta_913D/wlEmoticon-winkingsmile_2.png" /&gt;&lt;/p&gt;
&lt;p&gt;Of course, you have your choice of &lt;a title="Kalamazoo" target="_blank" href="http://www.sqlsaturday.com/84/eventhome.aspx"&gt;three&lt;/a&gt; &lt;a title="Toronto" target="_blank" href="http://www.sqlsaturday.com/93/eventhome.aspx"&gt;other&lt;/a&gt; &lt;a title="San Diego" target="_blank" href="http://www.sqlsaturday.com/95/eventhome.aspx"&gt;SQL Saturdays&lt;/a&gt; in other cities that day, but come on, you &lt;a title="And we'll be re-enacting the movie Highlander" target="_blank" href="https://twitter.com/#!/SirSQL/status/111986537058680833"&gt;really want to go to this one&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;#sqlsat89 #sqlsaturday #sqlkilt #sqlpass&lt;/p&gt;&lt;img src="/robv/aggbug/61348.aspx" width="1" height="1" /&gt;</content>
    </entry>
    <entry>
        <title>24 Hours of PASS: Whine, Whine, Whine</title>
        <link rel="alternate" type="text/html" href="http://weblogs.sqlteam.com/robv/archive/2011/09/07/24-hours-of-pass-whine-whine-whine.aspx" />
        <id>http://weblogs.sqlteam.com/robv/archive/2011/09/07/24-hours-of-pass-whine-whine-whine.aspx</id>
        <published>2011-09-07T12:12:12Z</published>
        <updated>2011-09-07T12:12:41Z</updated>
        <content type="html">&lt;p&gt;&lt;a href="http://www.sqlpass.org/24hours/fall2011/" target="_blank"&gt;24 Hours of Pass&lt;/a&gt; (or 24HOP) is a great program offered by &lt;a href="http://www.sqlpass.org/" target="_blank"&gt;PASS&lt;/a&gt; to provide free, online training for anyone who wants to learn more about SQL Server.  They routinely have the best SQL Server presenters available for these sessions, and attract hundreds, perhaps even a thousand attendees from around the world.  This is definitely one of the best things they've started doing in the past few years, and every session I've attended has been excellent.&lt;/p&gt;  &lt;p&gt;So why am I so grumpy about it?&lt;/p&gt;  &lt;p&gt;I'm not really, pretty much everything here is a minor annoyance that I can deal with.  However since they're so minor they seem to be things that can be easily corrected and would make the process much better. &lt;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://weblogs.sqlteam.com/images/weblogs_sqlteam_com/robv/Windows-Live-Writer/24-Hours-of-PASS-Whine-Whine-Whine_9070/wlEmoticon-smile_2.png" /&gt;&lt;/p&gt;  &lt;p&gt;First off, this is my biggest gripe, the registration page:&lt;/p&gt;  &lt;p&gt;&lt;a href="https://www323.livemeeting.com/lrs/8000181573/Registration.aspx?pageName=lj6378f4fhf5hpdm"&gt;https://www323.livemeeting.com/lrs/8000181573/Registration.aspx?pageName=lj6378f4fhf5hpdm&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;What grinds my gears about this?  I have to scroll alllllllllllllllllllllllllllll the way to bottom to actually register for the sessions.  This wouldn't be so bad except all the details of the session, including the presenter, is in a separate list at the top.  Both lists contain info the other does not, and scrolling between them to determine "Should I make time to listen to this?  Who is speaking at this time anyway?" is really unnecessary.&lt;/p&gt;  &lt;p&gt;My preference would be to keep the top list and add the checkboxes and schedule info in separate columns.  This is a full-width design, so there's plenty of space for this data, which is pretty small anyway.  The other huge benefit is halving the size of the page, which improves performance and lowers bandwidth usage considerably.  And if you know HTML/ASP.Net, and you view the page source, you can find PLENTY of other things that can be reduced even further.  (not just viewstate)&lt;/p&gt;  &lt;p&gt;One nice thing that PASS does is send iCal reminders to your email address so you can accept them to your calendar.  Again, they leave off the presenter in the appointment details, while still duplicating the meeting title in the body.  Sometimes I make decisions based on speaker rather than content (Natalie Portman is reading the Yellow Pages??? I'M THERE!) and having the speaker in the iCal is helpful.&lt;/p&gt;  &lt;p&gt;Next minor annoyances are the necessity for providing a company name, and the survey questions.  I know PASS needs to market themselves effectively, and they need information to do that, and since this is a free event it's really not worth complaining about, but why ask the survey question twice? (once at registration, once again when joining the LiveMeeting)  Same thing for the company name.  All of this should be tied to email address, so that's all I should need to enter when joining the LiveMeeting.&lt;/p&gt;  &lt;p&gt;The last one is also minor, but it irks me in this day and age of multiple browsers and the decline of Internet Explorer as a dominant platform.  The registration page was originally created in Visual Studio 2003, and has a lot of IE-specific crud representative of the browser situation of 2003. (IE5 references? really? and is the aforementioned viewstate big enough?)  This causes some grief with other browsers like Firefox, Chrome, and sometimes IE8 or 9.  And don't get me started on using the page on a Mac or in Safari.&lt;/p&gt;  &lt;p&gt;My main point is that PASS is an international organization, welcoming everyone from all levels of SQL Server proficiency, and in that spirit I think it would help to accommodate a wider range of browser software, especially since the registration page is extremely simple.  I recognize that this page is not hosted on the PASS website and may be maintained by some division of Microsoft, but to me that's even worse if MS can't update their own pages.  They've &lt;a title="about f---ing time...8 years ago!" href="http://news.cnet.com/8301-30685_3-10406468-264.html" target="_blank"&gt;deprecated&lt;/a&gt; IE6, so they don't need to maintain support on their own websites anymore.&lt;/p&gt;  &lt;p&gt;OK, I'll shut up now.&lt;/p&gt;  &lt;p&gt;#sqlpass #24HOP&lt;/p&gt;&lt;img src="/robv/aggbug/61347.aspx" width="1" height="1" /&gt;</content>
    </entry>
    <entry>
        <title>How to do an ER Diagram</title>
        <link rel="alternate" type="text/html" href="http://weblogs.sqlteam.com/robv/archive/2011/09/01/how-to-do-an-er-diagram.aspx" />
        <id>http://weblogs.sqlteam.com/robv/archive/2011/09/01/how-to-do-an-er-diagram.aspx</id>
        <published>2011-09-01T14:21:43Z</published>
        <updated>2011-09-01T14:27:23Z</updated>
        <content type="html">&lt;img src="/robv/aggbug/61345.aspx" width="1" height="1" /&gt;</content>
    </entry>
    <entry>
        <title>Acad-anemic</title>
        <link rel="alternate" type="text/html" href="http://weblogs.sqlteam.com/robv/archive/2011/08/30/acad-anemic.aspx" />
        <id>http://weblogs.sqlteam.com/robv/archive/2011/08/30/acad-anemic.aspx</id>
        <published>2011-08-30T16:15:53Z</published>
        <updated>2011-08-31T06:43:37Z</updated>
        <content type="html">&lt;img src="/robv/aggbug/61343.aspx" width="1" height="1" /&gt;</content>
    </entry>
    <entry>
        <title>T-SQL Tuesday #21 - Crap!</title>
        <link rel="alternate" type="text/html" href="http://weblogs.sqlteam.com/robv/archive/2011/08/10/t-sql-tuesday-21-crap.aspx" />
        <id>http://weblogs.sqlteam.com/robv/archive/2011/08/10/t-sql-tuesday-21-crap.aspx</id>
        <published>2011-08-10T18:09:47Z</published>
        <updated>2011-08-10T18:38:37Z</updated>
        <content type="html">&lt;p&gt;&lt;a style="TEXT-DECORATION: underline" alt="T-SQL Tuesday...on Wednesday" href="http://sqlblog.com/blogs/adam_machanic/archive/2011/08/03/t-sql-tuesday-21-a-day-late-and-totally-full-of-it.aspx"&gt;&lt;img style="PADDING-BOTTOM: 10px; PADDING-LEFT: 10px; PADDING-RIGHT: 10px; FLOAT: left; PADDING-TOP: 10px" width="150" height="150" alt="" src="http://sqlblog.com/blogs/adam_machanic/TSQLWednesday_2C948C01.jpg" /&gt;&lt;/a&gt;Adam Machanic's (&lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://sqlblog.com/blogs/adam_machanic/"&gt;blog&lt;/a&gt; | &lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://twitter.com/#!/AdamMachanic"&gt;twitter&lt;/a&gt;) ever popular &lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://sqlblog.com/blogs/adam_machanic/archive/tags/_2300_tsql2sday/default.aspx"&gt;T-SQL Tuesday series&lt;/a&gt; is being held on Wednesday this time, and the topic is…&lt;/p&gt;
&lt;p&gt;&lt;strike&gt;SHIT&lt;/strike&gt; CRAP.&lt;/p&gt;
&lt;p&gt;No, not fecal material.  But crap code.  Crap SQL.  Crap ideas that you thought were good at the time, or were forced to do due (doo-doo?) to lack of time.&lt;/p&gt;
&lt;p&gt;The challenge for me is to look back on my SQL Server career and find something that WASN'T crap.  Well, there's a lot that wasn't, but for some reason I don't remember those that well.  So the additional challenge is to pick one particular turd that I really wish I hadn't squeezed out.  Let's see if this outline fits the bill:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;An ETL process on text files; &lt;/li&gt;
    &lt;li&gt;That had to interface between SQL Server and an AS/400 system; &lt;/li&gt;
    &lt;li&gt;That didn't use SSIS (should have) or BizTalk (ummm, no) but command-line scripting, using Unix utilities(!) via: &lt;/li&gt;
    &lt;li&gt;xp_cmdshell; &lt;/li&gt;
    &lt;li&gt;That had to email reports and financial data, some of it sensitive &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yep, the &lt;strike&gt;stench&lt;/strike&gt; smell is coming back to me now, as if it was yesterday…&lt;/p&gt;
&lt;p&gt;As to why SSIS and BizTalk were not options, basically I didn't know either of them well enough to get the job done (and I still don't).  I also had a strict deadline of 3 days, in addition to all the other responsibilities I had, so no time to learn them.  And seeing how screwed up the rest of the process was:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Payment files from multiple vendors in multiple formats; &lt;/li&gt;
    &lt;li&gt;Sent via FTP, PGP encrypted email, or some other wizardry; &lt;/li&gt;
    &lt;li&gt;Manually opened/downloaded and saved to a particular set of folders (couldn't change this); &lt;/li&gt;
    &lt;li&gt;Once processed, had to be placed BACK in the same folders with the original archived; &lt;/li&gt;
    &lt;li&gt;x2 divisions that had to run separately; &lt;/li&gt;
    &lt;li&gt;Plus an additional vendor file in another format on a completely different schedule; &lt;/li&gt;
    &lt;li&gt;So that they could be MANUALLY uploaded into the AS/400 system (couldn't change this either, even if it was technically possible) &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I didn't feel so bad about the solution I came up with, which was naturally:&lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;Copy the payment files to the local SQL Server drives, using xp_cmdshell &lt;/li&gt;
    &lt;li&gt;Run batch files (via xp_cmdshell) to parse the different formats using sed, a Unix utility (this was before Powershell) &lt;/li&gt;
    &lt;li&gt;Use other Unix utilities (join, split, grep, wc) to process parsed files and generate metadata (size, date, checksum, line count) &lt;/li&gt;
    &lt;li&gt;Run sqlcmd to execute a stored procedure that passed the parsed file names so it would bulk load the data to do a comparison &lt;/li&gt;
    &lt;li&gt;bcp the compared data out to ANOTHER text file so that I could grep that data out of the original file &lt;/li&gt;
    &lt;li&gt;Run another stored procedure to import the matched data into SQL Server so it could process the payments, including file metadata &lt;/li&gt;
    &lt;li&gt;Process payment batches and log which division and vendor they belong to &lt;/li&gt;
    &lt;li&gt;Email the payment details to the finance group (since it was too hard for them to run a web report with the same data…which they ran anyway to compare the emailed file against…which always matched, surprisingly) &lt;/li&gt;
    &lt;li&gt;Email another report showing unmatched payments so they could manually void them…about 3 months afterward &lt;/li&gt;
    &lt;li&gt;All in "Excel" format, using xp_sendmail (SQL 2000 system) &lt;/li&gt;
    &lt;li&gt;Copy the unmatched data back to the original folder locations, making sure to match the file format exactly (if you've ever worked with &lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://en.wikipedia.org/wiki/Automated_Clearing_House"&gt;ACH&lt;/a&gt; files, you'll understand why this sucked) &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you're one of the 10 people who have read my &lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://weblogs.sqlteam.com/robv/default.aspx"&gt;blog&lt;/a&gt; before, you know that &lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://weblogs.sqlteam.com/robv/category/128.aspx"&gt;I love the DOS "for" command&lt;/a&gt;.  Like passionately.  Like &lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://www.imdb.com/title/tt0093779/"&gt;fairy-tale love&lt;/a&gt;.  So my batch files were riddled with for loops, nested within other for loops, that called other batch files containing for loops.  I think there was one section that had 4 or 5 nested for commands.  It was wrong, disturbed, and completely un-maintainable by anyone, even myself.  Months, even a year, after I left the company I got calls from someone who had to make a minor change to it, and they called me to talk them out of spraying the office with an AK-47 after looking at &lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://en.wikipedia.org/wiki/Medusa"&gt;this code&lt;/a&gt;.  &lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://www.imdb.com/title/tt0708433/"&gt;(for you Star Trek TOS fans)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The funniest part of this, well, one of the funniest, is that I made the deadline…sort of, I was only a day late…and the DAMN THING WORKED practically unchanged for 3 years.  Most of the problems came from the manual parts of the overall process, like forgetting to decrypt the files, or missing/late files, or saved to the wrong folders.  I'm definitely not trying to toot my own horn here, because this was truly one of the dumbest, crappiest solutions I ever came up with.  Fortunately as far as I know it's no longer in use and someone has written a proper replacement.  Today I would knuckle down and do it in &lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://sqlvariant.com/wordpress/index.php/2011/01/sql-smackdown-ssis-vs-powershell/"&gt;SSIS or Powershell&lt;/a&gt;, even if it took me weeks to get it right.&lt;/p&gt;
&lt;p&gt;The real lesson from this crap code is to make things MAINTAINABLE and UNDERSTANDABLE.  sed scripting regular expressions doesn't fit that criteria in any way.  If you ever find yourself under pressure to do something fast at all costs, DON'T DO IT.  Stop and consider long-term maintainability, not just for yourself but for others on your team.  If you can't explain the basic approach in under 5 minutes, it ultimately won't succeed.  &lt;/p&gt;
&lt;p&gt;And while you may love to leave all that crap behind, it may follow you anyway, and you'll step in it again.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p style="FONT-SIZE: smaller"&gt;P.S. - if you're wondering about all the manual stuff that couldn't be changed, it was because the entire process had gone through &lt;a style="TEXT-DECORATION: underline" target="_blank" href="http://en.wikipedia.org/wiki/Six_sigma"&gt;Six Sigma&lt;/a&gt;, and was deemed the best possible way.  Phew!  Talk about stink!&lt;/p&gt;&lt;img src="/robv/aggbug/61333.aspx" width="1" height="1" /&gt;</content>
    </entry>
    <entry>
        <title>I spoke at SQL Saturday #77 and all I got was this really awesome speaker's shirt!</title>
        <link rel="alternate" type="text/html" href="http://weblogs.sqlteam.com/robv/archive/2011/06/17/i-spoke-at-sql-saturday-77-and-all-i-got.aspx" />
        <id>http://weblogs.sqlteam.com/robv/archive/2011/06/17/i-spoke-at-sql-saturday-77-and-all-i-got.aspx</id>
        <published>2011-06-17T17:39:00Z</published>
        <updated>2011-06-17T17:45:23Z</updated>
        <content type="html">&lt;style type="text/css"&gt;&lt;![CDATA[
 a {text-decoration: underline;}]]&gt;&lt;/style&gt;
&lt;p&gt;Yeah, it was 2 weeks ago, but I'm finally blogging about something!&lt;/p&gt;
&lt;p&gt;I presented &lt;em&gt;&lt;strong&gt;Revenge: The SQL!&lt;/strong&gt;&lt;/em&gt; at &lt;a target="_blank" href="http://www.sqlsaturday.com/77/eventhome.aspx"&gt;SQL Saturday #77&lt;/a&gt; in Pensacola on June 4.  The session abstract is &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=77&amp;amp;sessionid=4262"&gt;here&lt;/a&gt;, and you can download the slides from that page too.  You can see how I look in the speaker's shirt &lt;a target="_blank" href="http://yfrog.com/h3erldmej"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Overall it went pretty well.  I discovered a new bit of evil just that morning and in a carefully considered, agonizing decision-making process that was full documented, tested, and approved…nah, I just went ahead and added it at the last minute.  Which worked out even better than (not) planned, since it screwed me up a bit and made my point perfectly.  I had a few fans in the audience, and one of them recorded it for &lt;strike&gt;blackmail material&lt;/strike&gt; posterity.&lt;/p&gt;
&lt;p&gt;I'd like to thank Karla Landrum (&lt;a target="_blank" href="http://karlalandrum.wordpress.com/"&gt;blog&lt;/a&gt; | &lt;a target="_blank" href="http://twitter.com/#!/KarlaKay22"&gt;twitter&lt;/a&gt;) and all the volunteers for putting together such a great event, and for being kind enough to let me present. (Note to Karla: I'll get the next $100 to you as soon as I can.  Might need a few extra days on the next $100.)&lt;/p&gt;
&lt;p&gt;Thanks to Audrey (&lt;a target="_blank" href="http://datachix.com/"&gt;blog&lt;/a&gt; | &lt;a target="_blank" href="http://twitter.com/#!/Datachix2"&gt;twitter&lt;/a&gt;), Peg, and Dorothy for attending and keeping the heckling down.  Thanks also to Aaron (&lt;a target="_blank" href="http://sqlvariant.com/wordpress/"&gt;blog&lt;/a&gt; | &lt;a target="_blank" href="http://twitter.com/#!/SQLvariant"&gt;twitter&lt;/a&gt;) for providing room and board and also not heckling.  Thanks to Julie (&lt;a target="_blank" href="http://datachix.com/"&gt;blog&lt;/a&gt; | &lt;a target="_blank" href="http://twitter.com/#!/Datachix1"&gt;twitter&lt;/a&gt;) for coming up with the title for the presentation.  (boo to Julie for getting sick and bailing out on us)  And thanks to all of them for listening to a preview and offering their suggestions and advice!&lt;/p&gt;
&lt;p&gt;Cross your fingers that I get accepted at &lt;a target="_blank" href="http://www.sqlsaturday.com/81/eventhome.aspx"&gt;SQL Saturday 81 in Birmingham&lt;/a&gt;, &lt;a target="_blank" href="http://www.sqlsaturday.com/85/eventhome.aspx"&gt;SQL Saturday 85 in Orlando&lt;/a&gt;, or &lt;a target="_blank" href="http://www.sqlsaturday.com/89/eventhome.aspx"&gt;SQL Saturday 89 in Atlanta&lt;/a&gt;, or just attend them anyway!&lt;/p&gt;&lt;img src="/robv/aggbug/61309.aspx" width="1" height="1" /&gt;</content>
    </entry>
    <entry>
        <title>HSSFS Part 2.1 - Parsing @@VERSION</title>
        <link rel="alternate" type="text/html" href="http://weblogs.sqlteam.com/robv/archive/2010/10/05/hssfs-part-2-1-parsing-version.aspx" />
        <id>http://weblogs.sqlteam.com/robv/archive/2010/10/05/hssfs-part-2-1-parsing-version.aspx</id>
        <published>2010-10-04T17:32:29Z</published>
        <updated>2010-10-05T16:38:34Z</updated>
        <content type="html">&lt;p&gt;For &lt;a target="_blank" href="http://weblogs.sqlteam.com/robv/archive/2010/10/02/handy-sql-server-functions-series-hssfs-part-2-0-prelude.aspx"&gt;Part 2&lt;/a&gt; of the &lt;a target="_blank" href="http://weblogs.sqlteam.com/robv/category/351.aspx"&gt;Handy SQL Server Function Series&lt;/a&gt; I decided to tackle parsing useful information from the &lt;font color="#ff00ff"&gt;@@VERSION&lt;/font&gt; function, because I am an idiot.  It turns out I was confused about &lt;font color="#ff00ff"&gt;CHARINDEX()&lt;/font&gt; vs. &lt;font color="#ff00ff"&gt;PATINDEX()&lt;/font&gt; and it pretty much invalidated my original solution.  All is not lost though, this mistake turned out to be informative for me, and hopefully for you.&lt;/p&gt;
&lt;p&gt;Referring back to the "Version" view in &lt;a target="_blank" href="http://weblogs.sqlteam.com/robv/archive/2010/10/02/handy-sql-server-functions-series-hssfs-part-2-0-prelude.aspx"&gt;the prelude&lt;/a&gt; I started with the following query to extract the version number:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;SELECT DISTINCT &lt;/span&gt;SQLVersion&lt;span style="COLOR: gray"&gt;, &lt;/span&gt;&lt;span style="COLOR: magenta"&gt;SUBSTRING&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;VersionString&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;PATINDEX&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: red"&gt;'%-%'&lt;/span&gt;&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;VersionString&lt;span style="COLOR: gray"&gt;)+&lt;/span&gt;2&lt;span style="COLOR: gray"&gt;, &lt;/span&gt;12&lt;span style="COLOR: gray"&gt;) &lt;/span&gt;VerNum
&lt;span style="COLOR: blue"&gt;FROM VERSION
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;I used &lt;font color="#ff00ff"&gt;PATINDEX()&lt;/font&gt; to find the first hyphen "-" character in the string, since the version number appears 2 positions after it, and got these results:&lt;/p&gt;
&lt;a name="first"&gt;&lt;/a&gt;
&lt;pre class="code"&gt;SQLVersion  VerNum
----------- ------------
2000        8.00.2055 (I
2005        9.00.3080.00
2005        9.00.4053.00
2008        10.50.1600.1&lt;/pre&gt;
&lt;p&gt;As you can see it was good enough for most of the values, but not for the SQL 2000 &lt;font color="#ff00ff"&gt;@@VERSION&lt;/font&gt;.  You'll notice it has only 3 version sections/octets where the others have 4, and the &lt;font color="#ff00ff"&gt;SUBSTRING()&lt;/font&gt; grabbed the non-numeric characters after.  To properly parse the version number will require a non-fixed value for the 3rd parameter of &lt;font color="#ff00ff"&gt;SUBSTRING()&lt;/font&gt;, which is the number of characters to extract.&lt;/p&gt;
&lt;p&gt;The best value is the position of the first space to occur after the version number (VN), the trick is to figure out how to find it.  Here's where my confusion about &lt;font color="#ff00ff"&gt;PATINDEX()&lt;/font&gt; came about.  The &lt;font color="#ff00ff"&gt;CHARINDEX()&lt;/font&gt; function has a handy optional 3rd parameter:&lt;/p&gt;
&lt;pre&gt;CHARINDEX (expression1 ,expression2 [ ,start_location ] )&lt;/pre&gt;
&lt;p&gt;While &lt;font color="#ff00ff"&gt;PATINDEX()&lt;/font&gt;:&lt;/p&gt;
&lt;pre&gt;PATINDEX ('%pattern%',expression )&lt;/pre&gt;
&lt;p&gt;Does not.  I had expected to use &lt;font color="#ff00ff"&gt;PATINDEX()&lt;/font&gt; to start searching for a space AFTER the position of the VN, but it doesn't work that way.  Since there are plenty of spaces before the VN, I thought I'd try &lt;font color="#ff00ff"&gt;PATINDEX()&lt;/font&gt; on another character that doesn't appear before, and tried "(":&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;SELECT &lt;/span&gt;SQLVersion&lt;span style="COLOR: gray"&gt;, &lt;/span&gt;&lt;span style="COLOR: magenta"&gt;SUBSTRING&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;VersionString&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;PATINDEX&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: red"&gt;'%-%'&lt;/span&gt;&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;VersionString&lt;span style="COLOR: gray"&gt;)+&lt;/span&gt;2&lt;span style="COLOR: gray"&gt;, &lt;/span&gt;&lt;span style="COLOR: magenta"&gt;PATINDEX&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: red"&gt;'%(%'&lt;/span&gt;&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;VersionString&lt;span style="COLOR: gray"&gt;))
&lt;/span&gt;&lt;span style="COLOR: blue"&gt;FROM VERSION
&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately this messes up the length calculation and yields:&lt;/p&gt;
&lt;pre class="code"&gt;SQLVersion  VerNum
----------- ---------------------------
2000        8.00.2055 (Intel X86) 
    Dec 16 2008 19:4
2005        9.00.3080.00 (Intel X86) 
    Sep  6 2009 01:
2005        9.00.4053.00 (Intel X86) 
    May 26 2009 14:
2008        10.50.1600.1 (Intel X86) 
    Apr
2008        10.50.1600.1 (X64) 
    Apr 2 20&lt;/pre&gt;
&lt;p&gt;Yuck.  The problem is that &lt;font color="#ff00ff"&gt;PATINDEX()&lt;/font&gt; returns position, and &lt;font color="#ff00ff"&gt;SUBSTRING()&lt;/font&gt; needs length, so I have to subtract the VN starting position:&lt;/p&gt;
&lt;pre class="code"&gt;&lt;span style="COLOR: blue"&gt;SELECT &lt;/span&gt;SQLVersion&lt;span style="COLOR: gray"&gt;, &lt;/span&gt;&lt;span style="COLOR: magenta"&gt;SUBSTRING&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;VersionString&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;PATINDEX&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: red"&gt;'%-%'&lt;/span&gt;&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;VersionString&lt;span style="COLOR: gray"&gt;)+&lt;/span&gt;2&lt;span style="COLOR: gray"&gt;, &lt;/span&gt;&lt;span style="COLOR: magenta"&gt;PATINDEX&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: red"&gt;'%(%'&lt;/span&gt;&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;VersionString&lt;span style="COLOR: gray"&gt;)-&lt;/span&gt;&lt;span style="COLOR: magenta"&gt;PATINDEX&lt;/span&gt;&lt;span style="COLOR: gray"&gt;(&lt;/span&gt;&lt;span style="COLOR: red"&gt;'%-%'&lt;/span&gt;&lt;span style="COLOR: gray"&gt;,&lt;/span&gt;VersionString&lt;span style="COLOR: gray"&gt;)) &lt;/span&gt;VerNum
&lt;span style="COLOR: blue"&gt;FROM VERSION&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;And the results are:&lt;/p&gt;
&lt;pre class="code"&gt;SQLVersion  VerNum
----------- --------------------------------------------------------
2000        8.00.2055 (I
2005        9.00.4053.00 (I
&lt;font color="#ff0000"&gt;Msg 537, Level 16, State 2, Line 1
Invalid length parameter passed to the LEFT or SUBSTRING function.&lt;/font&gt;&lt;/pre&gt;
&lt;p&gt;Ummmm, whoops.  Turns out SQL Server 2008 R2 includes "(RTM)" before the VN, and that causes the length to turn negative.&lt;/p&gt;
&lt;p&gt;So now that that blew up, I started to think about matching digit and dot (.) patterns.  Sadly, a quick look at the &lt;a href="#first"&gt;first set of results&lt;/a&gt; will quickly scuttle that idea, since different versions have different digit patterns and lengths.&lt;/p&gt;
&lt;p&gt;At this point (which took far longer than I wanted) I decided to cut my losses and redo the query using &lt;font color="#ff00ff"&gt;CHARINDEX()&lt;/font&gt;, which I'll cover in Part 2.2.  &lt;/p&gt;
&lt;p&gt;So to do a little post-mortem on this technique:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;&lt;font color="#ff00ff"&gt;PATINDEX()&lt;/font&gt; doesn't have the flexibility to match the digit pattern of the version number; &lt;/li&gt;
    &lt;li&gt;&lt;font color="#ff00ff"&gt;PATINDEX()&lt;/font&gt; doesn't have a "start" parameter like CHARINDEX(), that allows us to skip over parts of the string; &lt;/li&gt;
    &lt;li&gt;The &lt;font color="#ff00ff"&gt;SUBSTRING()&lt;/font&gt; expression is getting pretty complicated for this relatively simple task! &lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This doesn't mean that &lt;font color="#ff00ff"&gt;PATINDEX()&lt;/font&gt; isn't useful, it's just not a good fit for this particular problem.  I'll include a version in the next post that extracts the version number properly.&lt;/p&gt;
&lt;p&gt;UPDATE: Sorry if you saw the unformatted version of this earlier, I'm on a quest to find blog software that ACTUALLY WORKS.&lt;/p&gt;&lt;img src="/robv/aggbug/61210.aspx" width="1" height="1" /&gt;</content>
    </entry>
    <entry>
        <title>HSSFS Part 3: SQL Saturday is Awesome!  And DEFAULT_DOMAIN(), and how I found it</title>
        <link rel="alternate" type="text/html" href="http://weblogs.sqlteam.com/robv/archive/2010/10/04/hssfs-part-3-sql-saturday-is-awesome-and-default_domain-and.aspx" />
        <id>http://weblogs.sqlteam.com/robv/archive/2010/10/04/hssfs-part-3-sql-saturday-is-awesome-and-default_domain-and.aspx</id>
        <published>2010-10-04T10:31:09Z</published>
        <updated>2010-10-04T11:00:37Z</updated>
        <content type="html">&lt;p&gt;&lt;!--  a {text-decoration: underline; }  --&gt;Just a quick post I should've done yesterday but I was recovering from &lt;a title="SQL Saturday Rocks!" target="_blank" href="http://www.sqlsaturday.com/48/eventhome.aspx"&gt;SQL Saturday #48 in Columbia, SC&lt;/a&gt;, where &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=48&amp;amp;sessionid=2379"&gt;I went to&lt;/a&gt; &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=48&amp;amp;sessionid=2193"&gt;some&lt;/a&gt; &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=48&amp;amp;sessionid=2252"&gt;really excellent&lt;/a&gt; sessions by some &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=48&amp;amp;sessionid=2374"&gt;very&lt;/a&gt; &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=48&amp;amp;sessionid=2302"&gt;smart&lt;/a&gt; &lt;a target="_blank" href="http://www.sqlsaturday.com/viewsession.aspx?sat=48&amp;amp;sessionid=2164"&gt;experts&lt;/a&gt;.  If you have not yet attended a &lt;a title="Have I said how much SQL Saturday Rocks? Yes, I did, go back and check." target="_blank" href="http://www.sqlsaturday.com/default.aspx"&gt;SQL Saturday&lt;/a&gt;, or its been more than 1 month since you last did, SIGN UP NOW!&lt;/p&gt;
&lt;p&gt;While searching the &lt;span style="COLOR: #ff00ff"&gt;OBJECT_DEFINITION&lt;/span&gt;() of SQL Server system procedures I stumbled across the &lt;span style="COLOR: #ff00ff"&gt;DEFAULT_DOMAIN()&lt;/span&gt; function in &lt;span style="COLOR: #800000"&gt;xp_grantlogin&lt;/span&gt; and &lt;span style="COLOR: #800000"&gt;xp_revokelogin&lt;/span&gt;.  I couldn't find any information on it in Books Online, and it's a very simple, self-explanatory function, but it could be useful if you work in a multi-domain environment.  It's also the kind of neat thing you can find by using this query:&lt;/p&gt;
&lt;pre style="FONT-FAMILY: 'andale mono', times"&gt;&lt;span style="COLOR: #0000ff"&gt;SELECT&lt;/span&gt; &lt;span style="COLOR: #ff00ff"&gt;OBJECT_SCHEMA_NAME&lt;/span&gt;([object_id]) object_schema, name
&lt;span style="COLOR: #0000ff"&gt;FROM&lt;/span&gt; &lt;span style="COLOR: #008000"&gt;sys.all_objects&lt;/span&gt;
&lt;span style="COLOR: #0000ff"&gt;WHERE&lt;/span&gt; &lt;span style="COLOR: #ff00ff"&gt;OBJECT_DEFINITION&lt;/span&gt;([object_id]) LIKE &lt;span style="COLOR: #ff0000"&gt;'%()%'&lt;/span&gt; 
&lt;span style="COLOR: #0000ff"&gt;ORDER BY&lt;/span&gt; 1,2
&lt;/pre&gt;
&lt;p&gt;I'll post some elaborations and enhancements to this query in a later post, but it will get you started exploring the functional SQL Server sea.&lt;/p&gt;
&lt;p&gt;UPDATE: I goofed earlier and said SQL Saturday #46 was in Columbia. It's actually SQL Saturday #48, and &lt;a title="Hey, they're only a few hundred miles and 2 weeks apart..." target="_blank" href="http://www.sqlsaturday.com/46/eventhome.aspx"&gt;SQL Saturday #46 was in Raleigh, NC&lt;/a&gt;.&lt;/p&gt;&lt;img src="/robv/aggbug/61209.aspx" width="1" height="1" /&gt;</content>
    </entry>
</feed>System.Web.HttpWriter
