Category: Blog

  • #SQLFamily Feud

    I’ve started a new project. Actually, I started this well over a year ago, but I lost track of it and last week, despite the craziness, I was reminded of the effort and decided to get it going.

    What is the Game?

    A few of us were chatting about fun things at events and someone came up with the idea of Family Feud.  I thought it was great and started collecting questions. I then began organizing them, thinking I’d send out the list to 1000 people and get lots of responses.

    We would have the data available, and distribute it to someone at an event, such as SQL Saturday, and allow them to run a game. A game typically is two teams competing against each other, trying to give the top answers to a particular questions. Sometimes there are 4 answers, sometimes 6 or 7, but the idea is to get three of the answers for a team to win points. The first team to buzz in, or in this case, maybe signal the moderator gets to answer, each person in turn.

    Three wrong answers and the other team gets one chance to answer and win the round.

    I envision that we’d allow each group to collect points in maybe two rounds, and then we’d have a final round. The final round is one person from each team answering a set of questions. I’d say we do 5 to keep it quick. The second person doesn’t hear the first person’s answers, and together they need 200 points, with the count of survey answers matching their answers being added to each sum. Duplicates are not allowed.

    It’s a little cumbersome to explain, but watch the show on YouTube to get an idea how it works.

    Delays and Distractions

    However, I wanted to narrow the field, and didn’t want to send this in the SSC newsletter to everyone. Perhaps that was a mistake, but in compiling my list of people, I got distracted. Building a large group to email to is tedious, and despite some OCD on my part, I also have a little Short-Attention-Span-Syndrome.

    I had a soft launch last week, posting the first survey on Twitter and getting 100 responses in a few hours. That was kind of cool.

    I’ve got 6 surveys, which is a good start. I’m thinking if this works, that I’ll look to run additional surveys and collect more data that can be used in the future.

    What’s Coming?

    I am planning to randomly announce surveys on the @SQLServerCentrl and @way0utwest Twitter accounts this week to try and get more responses, but distribute them around the entire #sqlfamily.

    If you want to participate, watch out for the #sqlfamilyfeud hashtag later this week and send your answers in quick.

    If you’re an event organizer and want a copy of the datasets, feel free to ping me.

  • Puzzled by T-SQL

    Live blogging this a bit as I try things. This will update a bit, so you’ll have to read through.

    Adam Machanic posted this: T-SQL Puzzle-How many rows will this return? SELECT*FROM(VALUES(1),(2))AS x(i)WHERE EXISTS(SELECT MAX(i)FROM(VALUES(1))AS y(i)WHERE y.i=x.i)

    I was in a doctor’s office waiting at the time, but I responded that I didn’t think one row was right. I didn’t have the chance to see what happened, so I couldn’t reason through what was happening. Maybe I should have been able to? Not sure.

    I got home and ran this (thanks, SQL Prompt):

    SELECT
         *
       FROM     ( VALUES ( 1), ( 2) ) AS x ( i )
       WHERE     EXISTS ( SELECT  MAX(y.i)
                        FROM
                        ( VALUES ( 1) ) AS y ( i )
                   WHERE
                     y.i = x.i );
    

    I get two rows back, a 1 and a 2. Very strange.

    I tried experimenting a bit. I created tables and put data in there. Maybe there’s something I don’t get in the VALUES() clause.

    CREATE TABLE mytable99 (id INT);
    CREATE TABLE mytable999 (id INT);
    GO
    INSERT dbo.mytable99
    ( id )
    VALUES
    ( 1 ), (2);
    INSERT dbo.mytable999
    ( id )
    VALUES
    ( 1 )
    ;
    GO
    SELECT
    *
    FROM
    dbo.mytable99 AS x
    WHERE
    EXISTS ( SELECT MAX(y.id)
            FROM dbo.mytable999 AS y
            WHERE y.id = x.id );
    
    

    Same result.

    Hmmm, Adam added a clue. Why does select max(1) work?

    2015-12-03 13_43_15-Photos

    I was guessing that max() operates on the scalar set of [1]. However I’m not sure.

    I then did this:

    UPDATE dbo.mytable999 SET id = 9;
    

    When I re-ran the query, still two rows. Without a match.

    Next I added another row to the first table.

    INSERT dbo.mytable99
    ( id)
    VALUES
    ( 3 );
    

    Now I get three rows.

    What I’m guessing (at this point) is that the correlated subquery returns a 1 for every row of the first table, so this means I get the size and shape of that table. The EXISTS() is always satisfied.

    I’ll be interested to learn what is happening, or if I’m right.

    Update: I’m not.

    Or semi-right.

    The exists is satisfied, but why?

    Adam posted a second hint asking me to remove the max(). I did that and got 1 row. Well that’s interesting. How does the aggregate affect the correlated subquery, and how does this affect the Exists().

    I decided to break down the query inside the EXISTS(). I did this with scalar values. Since I’ve been dealing with two rows, I used those two scalar values.

    	 SELECT
                    y.i --MAX(y.i)
                  FROM
                    ( VALUES ( 1) ) AS y ( i ) 
    			  WHERE
                    y.i = 1 ;
    
    	 SELECT
                    y.i --MAX(y.i)
                  FROM
                    ( VALUES ( 1) ) AS y ( i ) 
    			  WHERE
                    y.i = 2;
    

    With these queries, I get one row and zero rows, just an empty set. That makes sense in terms of why removing the MAX() gives me one row in the whole thing.

    Next I added the MAX back.

    	 SELECT
                    MAX(y.i)
                  FROM
                    ( VALUES ( 1) ) AS y ( i ) 
    			  WHERE
                    y.i = 1 ;
    
    	 SELECT
                    MAX(y.i)
                  FROM
                    ( VALUES ( 1) ) AS y ( i ) 
    			  WHERE
                    y.i = 2;
    

    Now I get one row for the first, and one row for the second? Huh? However the second set is a row with NULL in it. I checked the EXISTS() documentation, and sure enough, if there are rows, this returns true, even if the row has a null value. This isn’t the value of a row, but rather just its presence.

    I then did this to check:

    SELECT 'test' = 1
     WHERE EXISTS( SELECT * FROM mytable WHERE 1 = 0);
    
    SELECT 'test' = 1
     WHERE EXISTS( SELECT null);
    

    Sure enough, the first gives me an empty result set, while the second doesn’t.

    But why does MAX() return a row? I tried this with a simple query:

     SELECT MAX(i)
      FROM ( VALUES (1)) AS x(i)
      WHERE x.i = 2

    Which does return NULL. I did search and saw this explanation on SO, saying that the result of the MAX() for the group (where x.i=2) is undefined, hence the NULL. This is born out as you see here:

    CREATE TABLE mytable88(i INT);
    GO
    SELECT MAX(i) FROM dbo.mytable88 AS m;
    

    Strange. Certainly I wouldn’t have expected that from MAX(). I would have thought it was an empty set, but apparently that’s not the case.

  • Ending My Loop in PowerShell Early

    Another post for me that is simple and hopefully serves as an example for people trying to get blogging as#SQLNewBloggers.

    I was modifying my PowerShell (PoSh) script to download SQL Saturday files recently to not re-download files. However when I did this, I also realized that I didn’t necessarily want the script to run too long.

    One of the challenges of downloading the data is that I don’t know how many events exist. We don’t keep that number handy, and it changes regularly. One of the things I decided to do was run my process in a loop.

    While ($i -lt 9999) {

    That’s fine, but it’s not a great loop. It runs 9999 times, which isn’t what I want. It works, but it’s an unnecessary use of resources. However I don’t want to break the loop when the file file isn’t found. There have been issues generating a file, like #350, when #351 exists and is there.

    I decided to use a shortcut technique I had learned as a kid. I set a variable and then incremented it when I missed a file. When the increment reaches some value, I break the loop.

    I decided to use 12 as my number of missed. No good reason, but that’s what I picked. I started by putting a variable outside of the loop.

    $missedXML = 0
    While ($i -lt 9999) {

    Then I increment this variable in the CATCH section of my error handler.

    Catch 
    { 
      # if we can't load the file, assume we're done for now. 
      $missedXML++ 
      Write-Host "error with  #" $i 
    }

    Finally, I set up an IF loop at the bottom of the loop. If I’ve missed 12 times, I break the loop by setting the counter to the last value.

    $i = $i + 1
    if ($missedXML -ge 12) { 
     $i = 9999 
    }

    I tested this with some debugging information and what I found was that when I got to 494, I started missing files. As soon as I hit 12, the loop ended.

    Enhancement complete.

    SQLNewBlogger

    This post came about when I started working on the script. I made the modifications from the previous post and decided to also fix the extra loops with this technique.

    This post took about 10 minutes to write.

    References

    No resources needed here. I’ve got enough PoSh knowledge to handle this task myself.

  • Changing Scales and Creating Disappointment

    I got an email recently that notified me that session feedback from the Summit was available for my talk. I’d had a lot of people in the room, and was curious how things went. I think the session was OK, a little off on time, a few too many questions I tried to answer, and perhaps a bumpy flow.

    However when I got my scores, I had a 2.85 for the session overall, with various aspects of the talk being rated from 2.5 to 2.9.

    Well, I sucked.

    That was my first thought. I’ve been getting rated, and evaluating speakers on a 5 point scale for quite a few years at PASS events. I was surprised, and disappointed, and then a bit embarrassed that I hadn’t delivered a good talk at the Summit. Since I hadn’t delivered that talk in public anywhere prior to the conference, I thought I had made a big mistake. Apparently my practice that week in my hotel room had been for naught.

    However then I saw this note in another email: One of the changes this year was to move from a five point rating scale to a three-point scale.

    Hmmm, I missed that in my email somewhere, and didn’t notice this as I filled out a couple of session evaluations.

    I don’t think there’s anything wrong with changing the scale. Personally I like the 3 point scale, but it wasn’t a change I noticed. The first communication with speaker feedback didn’t mention this.

    Scale matters. Many of us know that by manipulating scales, we can make data look different, We can prove a point that might not be supported by a different presentation of the data on another scale.

    Our clients and business users come to know and expect the various ways we present data. They will start to internalize scales and interpret data based on their expectations. We can change scales, but we need to make it clear and visible that we have changed scales.

    Personally I would have appreciated the results being reported as:

    Overall Session Score: 2.85/3.00

    instead of

    Overall Session Score: 2.85

    That little extra information can mean a lot. Keep this in mind as you make fundamental changes to the way you present data.