SQL Awesomesauce

When the kids go to sleep, I stay up and blog.

» Font Size «

This morning, I told Twitter:

GOOD MORNING PARTY PEOPLE! I’M YELLING BECAUSE I’M SO FRICKIN EXCITED ABOUT TONIGHT’S WEBSHOW!!!!1!1one!!

One (I’ll assume a rather) newish follower asked, “OK I’ll bite, what web show?”  Ah, yes, some of you don’t really know us well. First, I’ll tell you about the new season, then I’ll reintroduce us, for the newbies.

DBAs @ Midnight Webshow Tonight!

We’re kicking off the new season off with a live taping on Friday, September 3 at 11pm CST on our DBAsAtMidnight Ustream channel. DBAs@Midnight veterans know that around 10:30pm, we turn on the cameras for an informal preshow.

I won’t give away any surprises, but I will drop some hints about tonight’s show. We will have, among other things:

  • A new set, sort of
  • Something music-y
  • A VERY VERY exciting announcement
  • New “bits”, as we call them (show segments)
  • UNICORNS THAT SHOOT RAINBOWS AND BACON!!  That’s not true, I’m sorry…I just got excited…

Who are you, again?

Now, let myself introduce……myself.

Hi, I’m Jen. I’m a SQL Server DBA/dev. I’m one half of the MidnightDBAs, started (and continued) by my husband, SQL Server MVP Sean McCown. We make free IT training videos, blogs, and a weekly webshow, all of which can be found at MidnightDBA.com.

And SEASON TWO of our DBAs@Midnight starts TONIGHT! Season one was great: we talked about hiring and firing and quitting, workplace idiots, good practices, fame and conventions, studying…we interviewed some of the great minds at SQLPASS09, had a lovely group talk in a hotel room about plagarism.

Lest ye get the wrong idea about our webshow, you should also know: We swore, we innuendoed, we snickered (what would the Latin be for that?), we spent a lot of time sneaking in “That’s what she said!”  One show in particular had a definition of “taint”, with visual aids (all perfectly SFW)….and we still managed to tie it back into IT. Here’s a short overview of one show in particular, just so you get an idea:

In short, we are generally NSFW, and a fair amount of fun for the like-minded. If you like, join us tonight for the livecast, or catch the posted video next week on MidnightDBA.com

Happy days,

Jen McCown

http://www.MidnightDBA.com/Jen

Today let’s expand on the logical processing order of SELECT that I mentioned in last week’s N Things Worth Knowing About SELECT blog.

We’re looking at the SELECT statement clauses in the order that the SQL engine logically processes them…we’ll even write it that way – it’ll look weird, but we’ll be reading it like the SQL engine does.

You can find more on SELECT’s logical processing order in BOL, and in Itzik Ben-Gan’s T-SQL Fundamentals and T-SQL Programming books.

Here’s our basic T-SQL query (using AdventureWorks):

SELECT P.Name ,
  P.ProductNumber ,
  P.Color ,
  P.StandardCost ,
  SC.Name [Category]
FROM Production.Product P
LEFT OUTER JOIN Production.ProductSubCategory SC ON P.ProductSubCategoryID = SC.ProductSubCategoryID
WHERE P.ProductSubCategoryID IS NOT NULL

If we get all pseudo-mathematical on this, we can say that there’s some theoretical set of rows that we’ll get back out of this query; each logical step – in order – further refines that set of rows until we get back the actual rowset we want.

FROM

The SQL engine starts with the FROM clause first, to see where the data’s coming from. In this case we’re pulling from the Product table…easy. So, the theoretical rowset right now is everything in the Product table. (You can think about each step passing on that theoretical rowset to the next step for further refinement.)

-- Logical order:

FROM Production.Product P

ON/JOIN

Next we look at the ON and JOIN clauses: JOIN tells us what data structure (remember, it doesn’t have to be a table) we’re hooking up with, and ON give us the criteria for hooking our result sets together. We’re still building our theoretical resultset here; a JOIN can either expand the resultset, or limit it.

-- Logical order:

FROM Production.Product P
ON P.ProductSubCategoryID = SC.ProductSubCategoryID
LEFT OUTER JOIN Production.ProductSubCategory SC

Notice that the ON clause is evaluated before the WHERE clause; so we have to understand that where we put a limiting clause (like Color=’black’) can make a huge difference in our resultset. In this case, including the search condition “color=’black’” in the ON clause makes no difference, because it’s a LEFT OUTER JOIN…it’s going to return all the rows from the left side – black, red, blue, etc. – regardless of the join condition. Go on, try it:

SELECT P.Name ,
  P.ProductNumber ,
  P.Color ,
  P.StandardCost ,
  SC.Name [Category]
FROM Production.Product P
LEFT OUTER JOIN Production.ProductSubCategory SC ON P.ProductSubCategoryID = SC.ProductSubCategoryID
AND P.color='black'
WHERE P.ProductSubCategoryID IS NOT NULL

Toldya. In the ON clause, we’re comparing resultsets to make a match in a specific way. In the WHERE clause, we’re limiting the resultset that we got. Now, if this were an inner join, we could include the color=’black’ in the ON clause; it would limit the resultset just as if we’d said it IN WHERE. But I’m still more likely to put that condition in the WHERE clause; it’s more “proper”, in the sense that if that query ever needs to change to an outer join, the condition belongs in WHERE.

WHERE

Speaking of where…this is clearly the place where we’d want to whittle our resultset down to just the rows that we really want.

-- Logical order:

FROM Production.Product P
ON P.ProductSubCategoryID = SC.ProductSubCategoryID
LEFT OUTER JOIN Production.ProductSubCategory SC
WHERE P.ProductSubCategoryID IS NOT NULL AND Color='black'

In this statement, it’s the last refinement we make to our resultset, so next the SQL engine would evaluate the SELECT clause to see what columns to pull, and our logically-ordered query would look like this:

-- Logical order:

FROM Production.Product P
ON P.ProductSubCategoryID = SC.ProductSubCategoryID
LEFT OUTER JOIN Production.ProductSubCategory SC
WHERE P.ProductSubCategoryID IS NOT NULL AND Color='black'
SELECT P.Name ,
  P.ProductNumber ,
  P.Color ,
  P.StandardCost ,
  SC.Name [Category]

But, there’s a lot more we can do in a SELECT statement, so let’s continue with a more complex query that includes GROUP BY, HAVING, and ORDER BY:

SELECT P.Color ,
  COUNT(*) ItemCount,
  MIN(P.StandardCost) MinCost ,
  MAX(P.StandardCost) MaxCost ,
  AVG(P.StandardCost) AvgCost ,
  SC.Name [Category]
FROM Production.Product P
LEFT OUTER JOIN Production.ProductSubCategory SC ON P.ProductSubCategoryID = SC.ProductSubCategoryID
WHERE P.ProductSubCategoryID IS NOT NULL
AND P.color='black'
AND AVG(P.StandardCost) > 100
GROUP BY SC.Name, P.color
HAVING AvgCost > 100

GROUP BY

After SQL gets the base rowset down (by evaluating FROM, JOIN/ON, and WHERE), it looks at the GROUP clause to see if we’re going to lump some rows together. Notice, by the way, that we STILL haven’t looked at the actual SELECT clause:

-- Logical order:

FROM Production.Product P
ON P.ProductSubCategoryID = SC.ProductSubCategoryID
LEFT OUTER JOIN Production.ProductSubCategory SC
WHERE P.ProductSubCategoryID IS NOT NULL AND Color='black'
GROUP BY SC.Name, P.color

Today we want some aggregate data about each category, so we’ll GROUP BY the category name and color – when grouping, anything that’s not an aggregate (SUM, MIN, MAX, COUNT, etc) in the select list, MUST to be in the GROUP BY clause.

HAVING

A quick bit of trivia: the HAVING clause doesn’t require a GROUP BY clause; in that case, it just behaves like a WHERE. Oh, and speaking of WHERE…why couldn’t we just put the “AND AVG(P.StandardCost) > 100″ in the WHERE clause? Isn’t it a limiting factor, just like Color and subcategoryID?

Well, yeah it is, but remember: SQL evaluated WHERE, then GROUP BY (the aggregation clause), and THEN the HAVING clause. The aggregate isn’t allowed in the WHERE clause, because at that point, SQL hadn’t heard anything about grouping data…all the rows were still autonomous. So, aggregates go in HAVING:

-- Logical order:

FROM Production.Product P
ON P.ProductSubCategoryID = SC.ProductSubCategoryID
LEFT OUTER JOIN Production.ProductSubCategory SC
WHERE P.ProductSubCategoryID IS NOT NULL AND Color='black'
GROUP BY SC.Name, P.color
HAVING AvgCost > 100

SELECT

After HAVING, SQL finally takes a look at the SELECT clause itself, and our theoretical resultset becomes an actual resultset.

-- Logical order:

FROM Production.Product P
ON P.ProductSubCategoryID = SC.ProductSubCategoryID
LEFT OUTER JOIN Production.ProductSubCategory SC
WHERE P.ProductSubCategoryID IS NOT NULL AND Color='black'
GROUP BY SC.Name, P.color
HAVING AvgCost > 100
SELECT P.Color ,
COUNT(*) ItemCount,
MIN(P.StandardCost) MinCost ,
MAX(P.StandardCost) MaxCost ,
AVG(P.StandardCost) AvgCost ,
SC.Name [Category]

DISTINCT, ORDER BY, TOP

From here, SQL will process DISTINCT (if we included it), then ORDER BY (if we included it), then TOP (ditto). Let’s go ahead and include an ORDER BY:

-- Logical order:

FROM Production.Product P
ON P.ProductSubCategoryID = SC.ProductSubCategoryID
LEFT OUTER JOIN Production.ProductSubCategory SC
WHERE P.ProductSubCategoryID IS NOT NULL AND Color='black'
GROUP BY SC.Name, P.color
HAVING AvgCost > 100
SELECT P.Color ,
  COUNT(*) ItemCount,
  MIN(P.StandardCost) MinCost ,
  MAX(P.StandardCost) MaxCost ,
  AVG(P.StandardCost) AvgCost ,
  SC.Name [Category]
ORDER BY AvgCost

Here’s a big mystery revealed: THIS is why the ORDER BY clause is the ONLY clause that can refer to column aliases: ORDER BY is the only full clause that’s evaluated after the aliases are! Put it this way: we read the query top down, while SQL saves the top for nearly last. When you shout an alias name at it in your WHERE, SQL has NO IDEA what on earth you’re talking about.

And….there you go. Happy days,

Jen

http://www.MidnightDBA.com/Jen

Welcome to our third installment of Sticky Bits. SOMEBODY on Twitter inspired this (was it you, LaRock?), but darned if I can’t remember who just now. Enjoy.

Click for full size

Feel free to print, link, or reuse…just don’t take my name off please.

-Jen

I know it’s been a long, hot, difficult August without your regularly scheduled DBAs at Midnight to entertain and gross you out…but we’re about to start up again. Introducing…

DBAs at Midnight, Season 2!!!

We’re going to have some really cool new stuff on the show this season, and we’re quite excited! 

Edit: I’m not saying what is or what isn’t gonna happen, but there MAY be any or all of the following: music, guests, flying monkeys, popcorn, cooking lessons, shoe tying seminars, a special secret ninja club, swearing, nonswearing, insinuations, allegations, and everything we were doing before. I’m. SO. Excited.

We’ll kick the season off with a live taping on Friday, September 3 at 11pm CST on our DBAsAtMidnight Ustream channel.

Our first show ever, 9/3/2009!

Our first show ever, 9/3/2009!

Surveys are dumb and boring, we know that. But they’re also helpful. If you feel like being a helpy helperson and making the show better, DO take our little survey:

 

Would you like the show in one 1-hour file, or four to five 15-minute files? (1/3, answer and click Next)



What do you like/dislike about the show? (2/3, answer and click Next)
How do you usually watch the DBAs@Midnight webshow? (3/3, answer and click Submit)







Happy days,

Jen

http://www.MidnightDBA.com/Jen

If you haven’t messed with them yet, you should know that CTEs (Common Table Expressions) - new in SQL Server 2005 – are actualy pretty #awesomesauce. A CTE is, in essence, a temporary view attached to your SELECT statement.  They’re good for a number of uses, not the least of which is separating out some processing logic (like aggregation) for better understandability, or to avoid the use of temporary tables in a stored procedure.

Here’s a very simple example, using the AdventureWorks database:

WITH Top50 ( EmployeeID, FirstName, LastName, JobTitle )
AS ( SELECT TOP 50
EmployeeID ,
FirstName ,
LastName ,
JobTitle
FROM HumanResources.vEmployee
ORDER BY EmployeeID
)
SELECT EmployeeID ,
FirstName ,
LastName ,
JobTitle
FROM Top50
WHERE LastName < 'N'
ORDER BY LastName, FirstName

“WITH Top50″ gives your CTE a name; the parentheses define the list of columns available. AS, of course, defines what data will be in the CTE…and then the SELECT in line 10 actually pulls data from the CTE.

A few important notes:

  • CTEs aren’t just for SELECT statements. They can be used with SELECT, INSERT, UPDATE, DELETE, MERGE, within SPs and triggers and functions, AND in CREATE VIEW statements.
  • This is one of the very few T-SQL statements that has a semicolon requirement: a statement preceding the CTE must end with a semicolon. For example:

SELECT 'We are starting!' -- AAAAH! No semicolon!!
WITH Top50 ( EmployeeID, FirstName, LastName, JobTitle )
AS ( SELECT TOP 50
EmployeeID ,
FirstName ,
LastName ,
JobTitle
FROM HumanResources.vEmployee
ORDER BY EmployeeID
)
SELECT EmployeeID ,
FirstName ,
LastName ,
JobTitle
FROM Top50
WHERE LastName < 'N'
ORDER BY LastName, FirstName

This will spit out the error “Msg 102, Level 15, State 1, Line 3 Incorrect syntax near ‘Top50′.” Slap a semicolon on that “SELECT 'We are starting!'“.

Two of my Favorite Things!

Recursion and Wil Wheaton

  • One of the megacool uses of CTEs is recursion. BOL gives a great outline and examples of usin a recursive CTE to pull back a hierarchical list of employees (the standard JOIN dbo.Employee M ON E.managerID = M.employeeID scenario).
  • You can also define MULTIPLE CTEs in a single statement, with the format:
    WITH <cteName> (<columns>) AS (<select statement>),
      <cteName (<columns>) AS (<select statement>)
    <SELECT statement>
    Here is a very academic example (no one would need THIS resultset!), just to show you how it looks:

 
WITH Top50 ( EmployeeID, FirstName, LastName, JobTitle )
AS ( SELECT TOP 50
  EmployeeID ,
  FirstName ,
  LastName ,
  JobTitle
FROM HumanResources.vEmployee
ORDER BY EmployeeID
),
Bottom50 ( FirstName, LastName, JobTitle ) -- second CTE!
AS ( SELECT TOP 50
  FirstName ,
  LastName ,
  JobTitle
FROM HumanResources.vEmployee
ORDER BY EmployeeID DESC
)
SELECT Top50.EmployeeID ,
  Top50.FirstName ,
  Top50.LastName ,
  Top50.JobTitle ,
  Bottom50.FirstName ,
  Bottom50.LastName
FROM Top50
INNER JOIN Bottom50 ON Top50.Title = Bottom50.Title
WHERE LastName < 'N'
ORDER BY LastName, FirstName

And there you go…roughly N things you should know about CTEs. For your enjoyment, here is some further reading from BOL:

Happy days,

Jen McCown

http://www.MidnightDBA.com/Jen

Whoa.

SELECT is this kind of Swiss Army Knife

SELECT is our bedrock, our foundation, our now-and-forever T-SQL multitasker…and it’s one of the most complicated structures available to us.  Here are a few things worth knowing about it, from the basic to the obscure. 


More-or-Less Basic Structure

There’s tons more that can go into the SELECT statement, of course, but the basic structure is: 

WITH <CTE>
SELECT <columns>
FROM <table
INNER | OUTER | FULL JOIN <table> ON <criteria>
WHERE <criteria>
GROUP BY <column(s)>
HAVING <criteria>
ORDER BY <columns>
 

Interesting side note: Did you know that the HAVING clause does not require a GROUP BY clause? Of course then, the HAVING just behaves like a WHERE. Still, that could help you out on Quiz Bowl night at PASS. 

And a more useful side note: In 2005 and later versions, you can ORDER BY columns that aren’t in your SELECT list. So I can SELECT FirstName, MiddleName FROM Table1 ORDER BY LastName, if I so choose. 

Data Sources

You can SELECT data from a constant (such as “SELECT 100″), a variable, a table, temporary table, table variable, view, or table-valued function. 

CTEs

If you haven’t messed with them, CTEs (Common Table Expressions) are actually pretty #awesomesauce. A CTE is, in essence, a temporary view attached to your select statement. Here’s very simple example: 

WITH JensTable (ID, Column1)
AS
(SELECT TOP 10 ID, Column1 FROM Jen.MyTable)
SELECT ID, Column1
FROM JensTable
WHERE ID < 500
 

“With ___” gives the CTE a name; the first parentheses define the columns that we can access; and the parenthetical SELECT (line 3) pulls data for our CTE.  One very important note: this is one of the very few T-SQL statements that has a semicolon requirement: a statement preceding the CTE must end with a semicolon. For example: 

SELECT 'We are starting!';
WITH JensTable (ID, Column1)
AS
(SELECT TOP 10 ID, Column1 FROM Jen.MyTable)
SELECT ID, Column1
FROM JensTable
WHERE ID < 500
 

“SELECT ‘We are starting!’” MUST end in a semicolon, or this batch will throw an error. 

Widgets You Can Throw Into SELECT

On top of the regular structure (of which nearly everything except the word “SELECT” is optional), you can also throw in 

  • TOP keyword, to get the top N or top X% rows. Use TOP <whatever> WITH TIES to get extra rows, if they have the same value as rows in the TOP list. 

Interesting side note: You can use TOP with INSERT and UPDATE statements (INSERT TOP (2) INTO Table1 (col1) SELECT col1 FROM MyTable ORDER BY col1), but it’s not constrained by the ORDER BY in the select statement…you’re essentially inserting two random rows. The workaround?  A TOP clause in the select statement (INSERT TOP (2) INTO Table1 (col1) SELECT TOP 2 col1 FROM MyTable ORDER BY col1). End of side note.  

  • DISTINCT, to get unique rows (NULLs are treated as equals, just this once)
  • INTO, to pipe your data into a very useful table or table variable.
  • FOR XML, if you’re into that kind of thing.
  • UNION, to stack one resultset on top of another  (column lists must be identically named/typed)
  • EXCEPT or INTERSECT, which is very like UNION (cols must be same in name and type), but instead of adding, you’re looking for rows that match (intersect) or that are missing from one side (except). This is rather like a shorthand JOIN, where you don’t have to write out all the criteria (A.col1 = B.Col1 AND A.col2 = B.Col2 etc etc).
  • Subqueries. It’s amazing the places you can stick subqueries, truly…BOL says “a subquery can be used anywhere an expression is allowed”.  That’s a whoooole nother article, though (or several!).

How SQL Server processes the SELECT statement

The BOL article on SELECT gives us the processing order of the select statement: 

  1. FROM
  2. ON
  3. JOIN
  4. WHERE
  5. GROUP BY
  6. WITH CUBE or WITH ROLLUP
  7. HAVING
  8. SELECT
  9. DISTINCT
  10. ORDER BY
  11. TOP

In other words, when SQL Server first looks at your select statement, it first wants to know where the data is coming from (FROM and ON). Then, if there are joins, it wants to know how to join them together…this limits or expands the resultset.  And so on. 

About a year ago, I reviewed Itzik Ben-Gan’s book “Inside MS SQL Server 2008: T-SQL Querying” (I called it “an absolute gold mine for T-SQL developers, both as a study guide and as a mark-it, underline-it, dogear-it reference”, and I stand by that).  Chapter 1 of that book gives the best discussion I’ve ever seen on logical query processing, and I urge you to run RIGHT out to Amazon and buy it, or at least borrow it from someone in your user group.


I think that’s a nice start on our SELECT statement trivia. What about you…what are your most/least favorite SELECT statement factlets?

Happy days,

Jen McCown

http://www.MidnightDBA.com/Jen

Our last Follow Friday, at the end of May, was mister Tim Mitchell of the NTSSUG board. I’m apparently following a theme this summer, for today’s Follow Friday is NTSSUG board candidate Ryan Adams (blog, Twitter)!  Ryan’s a SQL Server DBA who has been at the same company for…twelve years??  I don’t even know what you just said to me, man.

Guy's got more certs than a singles convention

Yesterday Ryan stood before the user group and told us why he’d be a good UG board member – I wasn’t listening, it was something about free Droids for everyone who votes for him, or something – and then went on to host one of the five discussion groups we had for the evening.  Okay, to tell the truth I waslistening, and the guy’s got some good ideas and a LOT of energy for the group.  Ryan’s been a volunteer and core team planner for SQL Saturday Dallas 2010, and is doing it again for SQL Saturday Dallas BI this fall. He blogs, he tweets, he (I believe) created the NTSSUG LinkedIn group. He’s on the planning committee for the upcoming HoustonSQL Saturday, for Codd’s sake!

Others have noticed…after SQL Sat in May, Stuart Ainsworth wrote on his blog:

Ryan Adams was the sponsor coordinator, and I watched him work those tables several times throughout the day.  That was a nice touch, and I hope the sponsors appreciated having someone who was available to them all the time to handle any issues that they may have had come up.

And Wes Brown had this to say from the vendor perspective:

Ryan Adams did a very good job keeping things coordinated up to the event. Making sure that everything we were entitled to we got. Always very responsive to emails and questions.

The day of I always had Ryan or one of the volunteers stop by between sessions and check that everything was good. I have always had a good experience with PASS events, but I’ve never had so many people checking on us before!

Ryan’s a hardworking, upbeat, all-around good guy with a good view of what’s good in the SQL community.  That’s a lotta “good”.  Go give him a follow, subscribe to the blog (be sure to read the one about how he handled SQLSat sponsor coordination), and give him a hard time because he doesn’t get Droid discounts.

Happy days,

Jen McCown

http://www.MidnightDBA.com/Jen

EDIT: We had the times wrong…Janis is speaking in the 6pm slot, and the discussion groups are durin the second hour.

The August NTSSUG meeting is tomorrow evening, starting at 6:15 pm.  Sean is done with this year’s series of 6pm classes on SSIS, so whatever shall we do with the extra time?

As it turns out, something pretty damn cool:

In the first hour (6:15 to 7:15) of [actually the second hour of] this month’s meeting, we’re experimenting with a new format.  We’re going to try to arrange four or five different small discussion groups to be run concurrently, and you’ll all get to choose which discussion you’d like to join.  We’ll break up into these groups, each of which will be led by either one or two moderators, and let the conversation carry where it will.  These will be conversations, not presentations, so bring your ideas, questions, or other items you’d like to discuss with your small group (though you’re welcome to just sit and listen if you prefer).

Would anyone like to guess who is leading one of tomorrow’s discussion groups?  Well, I’ll take a random guess. ME!  For the topic, I’ve chosen “Women in Technology“.  A user group friend rightly commented that it should be interesting to the women in the group, “and some dudes too”. :)

Aren't we cute? Now come to the meeting!

Those of you within a N-mile drive of Irving, TX should come down tomorrow for that, and for what sounds like an extremely interesting main stage session at 6:15pm 7:30pm: Janis Griffin’s “Tuna Helper – Proven Process for Tuning SQL“. Oh yeah, and giveaways and networking and getting to hang out with me and Sean, which is always big fun.

AND…

The NTSSUG board has also voted to add a position to the board (more info here).  Candidates will make a short address at the meeting tomorrow night, and then email voting ends on the 26th.  You should REALLY plan to be there for the speeches, certainly.

Big props to Confio Software for sponsoring…thanks guys!

See you tomorrow,

Jen McCown

http://www.MidnightDBA.com/Jen

Piggybacking tangentially off of Tim Mitchell’s (blog, Twitter) SSC editorial Turn a Bad Job into a Good Experience…yesterday I got some user questions about the department’s new password policy.  The policy is admittedly complex, especially considering half the place had been using the “kid’s name and ‘password’ scribbled on a post-it” philosophy of security. And, the new policy had been explained with a series of densley-packed PowerPoint slides.

So, I did what any good DBA would do: I cannibalized my comic strip into a The Oatmeal-style cheatsheet:

Sometimes, you gotta make your job fun, and you get to be useful at the same time.

Happy days,

Jen McCown

http://www.MidnightDBA.com

Natty!

A few facts:

  1. The PASS Community Summit is in (let’s see, SELECT DatePart(dy,’11/8/2010′) – DatePart(dy,GetDate()) = ) 84 days.
  2. Many members of the SQL community have decided to observe #SQLKilt day on Wednesday during the Summit, by wearing their nattiest kilt…even if speaking on that day.
  3. Scott Stauffer (SQLSocialite on Twitter) said last Wednesday, “Maybe we need to design a #SQLKilt Logo like #SQLRally and have SportKilt.com offer a discount for limited run?”
  4. I am fully supportive of all of the above.

So we at MidnightDBA have decided to host KILT FU: a contest to design and vote on the best SQL Kilt logo. The winner gets honor and fame and worldwide recognition (hey, we have readers in Slovenia and New Zealand, so that counts), and the #SQLKilt community gets an awesome logo to pin on their sweet, sweet kilts during the Summit. It’s all win!

Email Jen@MidnightDBA.com with your SQLKilt logo – you may enter up to three logos, if you’re feeling froggy – by Wednesday, September 1, and we’ll put up some sort of voting mechanism shortly after.