Lionel Clarke

Software Engineer - Red Gate Software

  • SQL Puzzle 9

    Posted Monday, January 07, 2008 5:56 PM | 46 Comments

    /*
    Happy New Year everybody! To help with the January blues, I thought it was time for another puzzle. The inspiration for this one comes from a SQL question posed by my girlfriend. She is a geologist and, on a recent field trip to Iceland, was wandering around with a GPS strapped to her head to make 3D representations of the side of hills. At the same time she was taking pictures of rocks on her digital camera (we have the best holiday snaps!).  Her question was this: how could she match the GPS points to the photos so that she had a rough idea of where all the photos were taken.

    So, on to the puzzle. We have a whole lot of points from our GPS and a whole lot of photos. Both the photos and the points have a time and date when they were taken. The puzzle is simple. I want to know which is the nearest point to each photo. Since we only have the time to go on, I want the point that is closest in terms time.

    So, for example, if we have a photo taken at 13:01 and points taken at 12:55, 13.00 and 13:06 then I want the photo to be at the point taken at 13:00. Any way of doing this in SQL is fine but the simpler your solution the better. If anyone wants to show off and do this in LINQ as well then I would be interested in your answer (as somebody who likes to write stored procedures I am a bit wary of LINQ but I am very interested in learning about it). I had to make up some imaginary data and my results are:

    PhotoName x           y           z
    --------- ----------- ----------- -----------
    Photo01   1           1           1
    Photo02   1           1           1
    Photo03   2           1           1
    Photo04   4           1           1
    Photo05   4           1           1
    Photo06   5           1           1
    Photo07   8           1           1
    Photo08   15          1           1
    Photo09   19          1           1
    Photo10   20          1           1
    Photo11   20          1           1
    Photo12   20          1           1
    Photo13   20          1           1
    Photo14   21          1           1
    Photo15   21          1           1


    On a final note, I would like to ask a huge favour of anyone reading this. I have been writing a tool to fill a SQL Server database with test data and have recently released a beta version. I think it is a really cool tool and is something I wanted back when I was a developer DBA. If you need a quick and easy way of filling a table with some example data you will almost certainly find this handy! We could really do with some feedback so if you have a spare moment please check it out! You can download it at:

    http://www.red-gate.com/messageboard/viewtopic.php?t=6140

    Most importantly, if you have any comments then please post them in the forum:

    http://www.red-gate.com/messageboard/viewforum.php?f=76

    Thanks and have fun,

    Lionel

    SET NOCOUNT ON

    DECLARE @Photos TABLE
    (
        PhotoName NVARCHAR(7) PRIMARY KEY,
        TimeTaken DATETIME
    )

    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo01', '2008-01-02 15:01:10.12')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo02', '2008-01-07 10:21:06.13')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo03', '2008-01-07 11:15:11.42')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo04', '2008-01-07 12:38:53.653')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo05', '2008-01-07 12:38:53.657')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo06', '2008-01-07 13:25:51.12')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo07', '2008-01-07 14:35:00.00')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo08', '2008-01-07 15:04:19.55')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo09', '2008-01-07 16:01:01.17')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo10', '2008-01-07 16:10:32.92')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo11', '2008-01-07 16:10:32.92')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo12', '2008-01-07 16:10:32.92')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo13', '2008-01-07 16:33:18.35')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo14', '2008-10-15 16:15:52.45')
    INSERT INTO @Photos(PhotoName, TimeTaken) VALUES ('Photo15', '2010-10-07 17:53:25.26')

    DECLARE @Locations TABLE
    (
        LocationID INT IDENTITY(1,1) PRIMARY KEY,
        x INT,
        y INT,
        z INT,
        TimeTaken DATETIME
    )

    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (1,1,1,  '2008-01-07 10:00:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (2,1,1,  '2008-01-07 11:05:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (3,1,1,  '2008-01-07 11:30:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (4,1,1,  '2008-01-07 12:30:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (5,1,1,  '2008-01-07 13:10:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (6,1,1,  '2008-01-07 14:10:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (7,1,1,  '2008-01-07 14:20:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (8,1,1,  '2008-01-07 14:30:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (9,1,1,  '2008-01-07 14:40:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (10,1,1, '2008-01-07 14:50:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (12,1,1, '2008-01-07 15:01:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (13,1,1, '2008-01-07 15:02:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (14,1,1, '2008-01-07 15:03:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (15,1,1, '2008-01-07 15:04:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (16,1,1, '2008-01-07 15:05:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (17,1,1, '2008-01-07 15:06:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (18,1,1, '2008-01-07 15:07:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (19,1,1, '2008-01-07 16:08:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (20,1,1, '2008-01-07 16:09:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (21,1,1, '2008-01-07 17:00:00.00')
    INSERT INTO @Locations(x,y,z, TimeTaken) VALUES (22,1,1, '2008-01-07 17:00:00.00')

    SET NOCOUNT OFF

  • SQL Puzzle 8

    Posted Tuesday, November 27, 2007 7:12 PM | 24 Comments

    /*
    So I thought it was just about time for another puzzle but I was having great difficulty in coming up with a new challenge.  Luckily Andras has posted a blog entry about how the
    POWERSUM function has been removed from SQL Server.

    http://www.simple-talk.com/community/blogs/andras/archive/2007/11/22/40021.aspx

    This puzzle is a nice simple one and is to write a single select statement that will return the same results as POWERSUM when run on the supplied table variable. The input values will be between 0 and 127 but it would be nice to see solutions that will scale to beyond that. Andras has posted an explanation of what POWERSUM does but if it is still unclear exactly what it does (The output seems to be the reverse of what I expect it to be!) add a comment to the blog and I will add some clarification. Have fun!

    Lionel

    */

    SET NOCOUNT ON

    DECLARE @Data TABLE
    (
        Col INT
    )

    INSERT INTO @Data(col)
        SELECT 1
    INSERT INTO @Data(col)
        SELECT 1
    INSERT INTO @Data(col)
        SELECT 2
    INSERT INTO @Data(col)
        SELECT 98
    INSERT INTO @Data(col)
        SELECT 31
    INSERT INTO @Data(col)
        SELECT 32
    INSERT INTO @Data(col)
        SELECT 32
    INSERT INTO @Data(col)
        SELECT 63
    INSERT INTO @Data(col)
        SELECT 17
    INSERT INTO @Data(col)
        SELECT 100
    INSERT INTO @Data(col)
        SELECT 56
    INSERT INTO @Data(col)
        SELECT 24
    INSERT INTO @Data(col)
        SELECT 17
    INSERT INTO @Data(col)
        SELECT 2
    INSERT INTO @Data(col)
        SELECT 127
    INSERT INTO @Data(col)
        SELECT 76
    INSERT INTO @Data(col)
        SELECT 84
    INSERT INTO @Data(col)
        SELECT 99
    INSERT INTO @Data(col)
        SELECT 12
    INSERT INTO @Data(col)
        SELECT 103
    SET NOCOUNT OFF

    -- This should return the same as
    -- SELECT POWERSUM(col) FROM @Data
    -- which is 0x0610028101000081001010009C000080
  • SQL Puzzle 7

    Posted Friday, October 26, 2007 10:53 AM | 104 Comments

    /*
    Well, it has been a while since I posted up a puzzle. I  blame this on the very unflattering picture of myself attached to the blog. This causes me a natural reluctance to put it in a position where people might see it! It is that and ...ahem... the cat ate my homework ...ahem... blog entry. Anyway, this puzzle has a couple of parts. Since I am short on ideas, the first part is the same as the second part just with one extra column.

    The puzzle is very simple. You have to move as much of the data as you can from the source tables to the destination tables. There is one restriction though;  you can only use one insert statement in each part! Extra points are definitely awarded for a solution that works in both SQL Server 2000 and 2005. So, to summarize, one insert statement to move data from Part1Source -> Part1Dest, and one insert stament to move Part2Source -> Part2Dest.

    Have fun!

    Lionel


    CREATE TABLE Part1Source
    (
        a INT,
        b INT,
        
        PRIMARY KEY (a,b)
    )
        
    INSERT INTO Part1Source VALUES (1,1)
    INSERT INTO Part1Source VALUES (1,2)
    INSERT INTO Part1Source VALUES (2,3)
    INSERT INTO Part1Source VALUES (7,2)
    INSERT INTO Part1Source VALUES (2,4)
    INSERT INTO Part1Source VALUES (5,5)
    INSERT INTO Part1Source VALUES (5,1)
    INSERT INTO Part1Source VALUES (5,3)
    INSERT INTO Part1Source VALUES (9,0)
    INSERT INTO Part1Source VALUES (11,2)

    CREATE TABLE Part1Dest
    (
        a INT UNIQUE,
        b INT UNIQUE,
        
        FOREIGN KEY (a,b)  REFERENCES Part1Source(a,b)    
    )

    ------------------------ Part 2 ------------------------

    CREATE TABLE Part2Source
    (
        a INT,
        b INT,
        c INT,
        
        PRIMARY KEY (a,b,c)
    )
        
        
    INSERT INTO Part2Source VALUES (1,1,2)
    INSERT INTO Part2Source VALUES (1,2,2)
    INSERT INTO Part2Source VALUES (2,3,1)
    INSERT INTO Part2Source VALUES (7,2,1)
    INSERT INTO Part2Source VALUES (2,4,7)
    INSERT INTO Part2Source VALUES (5,5,6)
    INSERT INTO Part2Source VALUES (5,1,4)
    INSERT INTO Part2Source VALUES (5,3,4)
    INSERT INTO Part2Source VALUES (9,0,1)
    INSERT INTO Part2Source VALUES (11,2,9)

    CREATE TABLE Part2Dest
    (
        a INT UNIQUE,
        b INT UNIQUE,
        c INT UNIQUE,
        
        FOREIGN KEY (a,b,c)  REFERENCES Part2Source(a,b,c)    
    )

    */
  • Sql Puzzle 6

    Posted Wednesday, June 28, 2006 8:25 PM | 0 Comments

    /* Just because I can't take another day of hassle for not posting up another puzzle here is a world cup themed one.  This puzzle is by a friend of mine called Tom Sillence.

    1) The first puzzle is to produce the group tables as seen on this page:
    http://news.bbc.co.uk/sport1/hi/football/world_cup_2006/tables/default.stm


    so we want a table with the following columns:
             Group: (e.g. "Angola's Group", "Mexico's Group")
             Country: the name of the country
             P: The number of games this country has played
             W: The number of wins the country has
             D: The number of draws this country has
             L: The number of losses this country has
             F: The number of goals this country has scored
             A: The number of goals this country has conceded
             GD: Goal difference which is (F - A)
             PTS: The total number of points
             Q: contains the letter Q if the team qualifies, otherwise empty string

    You have to work out which teams are together in each group by looking at who's played whom. You won't know which is group A, group B etc, so in my results I called them e.g. "Angola's group", picking an arbitrary team to represent the group.

    A quick reprise of world cup rules will tell us how the results should be sorted and who qualifies for the next round:

         - Each team gets 3 points for a win, 1 for a draw and 0 for a loss.
         - Teams who are tied on points are sorted by goal difference (GD) and then by goals scored (F)
         - The top two teams in each group qualify for the next round

    2) Uncomment the lines below the message "UNCOMMENT THESE LINES FOR QUESTION 2 and 3" at the end of this file :)

    (a) We've now removed some matches. Write a query that outputs which matches are still to be played. We want these columns:
    Group, TeamA, TeamB

    (b) Check that you can still output the group tables with these matches missing. For the purposes of working out the groups, you can assume no more than one match has been removed from each group.

    3) Write a query that outputs each team who still has a match left to play, and what they must do in order to qualify. This should include both the result (win/lose/draw) and the margin of victory or defeat that is necessary. There are lots of options for how to format this.

    In my solution I was trying to simulate what a commentator would say - I have a hardcoded string for each possible requirement. This is my output:

    Angola, currently lying third in their group, play Portugal
         Topping the group is impossible for them
         They must win here or it's curtains for them Portugal, currently lying first in their group, play Angola
         The result is immaterial, they have already qualified top
         Qualification is already assured
    Sweden, currently lying second in their group, play England
         They must win in order to top the group
         Qualification is already assured
    England, currently lying first in their group, play Sweden
         They only need a draw to qualify top
         Qualification is already assured
    France, currently lying third in their group, play Togo
         They can still reach first place if they win my a margin of 3 or more
         Their world cup hopes depend on a win by two or more goals Togo, currently lying last in their group, play France
        err...
        They're playing for pride now. Next stop for them is the airport.

    (6 row(s) affected)



    FOR THE RECORD:
    - I made use of a table variable to avoid retyping the same expression many times, but technically all of this can be done with a single query (it would be huge).

    - However, my solution to Q3 only takes account of points and goal difference, not goals scored. Can you do better?

    */

    set nocount on

    DECLARE @Results Table
    (
        TeamA VARCHAR(20) NOT NULL,
        TeamAGoals INT NOT NULL,
        TeamBGoals INT NOT NULL,    
        TeamB VARCHAR(20) NOT NULL
    )

    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Saudi Arabia',0,1,'Spain')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Switzerland',2,0,'South Korea')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Togo',0,2,'France')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Ukraine',1,0,'Tunisia')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Croatia',2,2,'Australia')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Czech Republic',0,2,'Italy')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Ghana',2,1,'USA')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Japan',1,4,'Brazil')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Holland',0,0,'Argentina')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Angola',1,1,'Iran')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Ivory Coast',3,2,'Serbia & Montenegro')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Portugal',2,1,'Mexico')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Costa Rica',1,2,'Poland')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Ecuador',0,3,'Germany')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Paraguay',2,0,'Trinidad and Tobago')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Sweden',2,2,'England')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Saudi Arabia',0,4,'Ukraine')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Spain',3,1,'Tunisia')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Togo',0,2,'Switzerland')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Brazil',2,0,'Australia')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('South Korea',1,1,'France')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Japan',0,0,'Croatia')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Czech Republic',0,2,'Ghana')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Italy',1,1,'USA')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Portugal',2,0,'Iran')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Argentina',6,0,'Serbia & Montenegro')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Holland',2,1,'Ivory Coast')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Mexico',0,0,'Angola')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Ecuador',3,0,'Costa Rica')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('England',2,0,'Trinidad and Tobago')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Sweden',1,0,'Paraguay')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Germany',1,0,'Poland')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Spain',4,0,'Ukraine')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Tunisia',2,2,'Saudi Arabia')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Brazil',1,0,'Croatia')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Switzerland',0,0,'France')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('South Korea',2,1,'Togo')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Australia',3,1,'Japan')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES('Italy',2,0,'Ghana')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('USA',0,3,'Czech Republic')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Angola',0,1,'Portugal')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Mexico',3,1,'Iran')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Serbia & Montenegro',0,1,'Holland')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Argentina',2,1,'Ivory Coast')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('England',1,0,'Paraguay')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Trinidad and Tobago',0,0,'Sweden')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Germany',4,2,'Costa Rica')
    INSERT INTO @Results(TeamA, TeamAGoals, TeamBGoals, TeamB)
        VALUES ('Poland',0,2,'Ecuador')

    ---- UNCOMMENT THESE LINES FOR QUESTION 2 and 3:
    /*
      delete from @results where teamA = 'Togo' and teamb = 'France'
      delete from @results where teamA = 'Sweden' and teamb = 'England'
      delete from @results where teamA = 'Angola' and teamb = 'Portugal'
      --make this a draw so the france match is interesting :
      update @results set teambgoals = 2
         where teamA = 'Switzerland' and teamb = 'South Korea'
    */

  • Sql Puzzle 5

    Posted Friday, December 30, 2005 5:27 PM | 2 Comments

    /*
    I hope that everybody had a good Christmas. I apologize for the lack of new puzzles but I have been using up the remains of my Holiday. Since it is the New Year I thought we should start it off with a nice easy but fun puzzle.

    Recently I have been struggling writing some internal Red Gate reports and while trying to get Reporting Services to draw bar graphs I thought wouldn’t it be much easier if we could just use SQL Server to generate all these reports internally. So this week’s puzzle is simple. Given some sales results generate an ASCII art bar chart representing the results. Whereas previous puzzles had either a right or a wrong answer with this one I would like to encourage a bit of competition so let’s see who can product the best looking ASCII art chart.

    Since space is limited I am only going to give people 4 columns to put on the chart. One column for each quarter of the year. The sales data is in a table cunningly labeled @SalesResults. This table has a column for which quarter of the year the results belong to which is a number from 1 to 4. There is also an AmountSold column for the amount of things sold in that quarter. I am also giving you a helper table called Sequence which just contains the numbers 0 to 100. A sequence table is the Swiss Army Knife of all database tables and is a very useful thing in any database. As usual with these puzzles you should be done with one top level select statement though you can use as many derived tables subselects and unions as you like. Defiantly no DDL, variables or Transact SQL Control statements like IF and WHILE. My solution is as follows:

    20 |                                        
       |                                        
       |                                        
       |                                        
       |                                        
       |                         ----           
       |                        |    |          
       |                        |    |          
       |     ----               |    |     ----
       |    |    |              |    |    |    |
    10 |    |    |              |    |    |    |
       |    |    |     ----     |    |    |    |
       |    |    |    |    |    |    |    |    |
       |    |    |    |    |    |    |    |    |
       |    |    |    |    |    |    |    |    |
       |    |    |    |    |    |    |    |    |
       |    |    |    |    |    |    |    |    |
       |    |    |    |    |    |    |    |    |
       |    |    |    |    |    |    |    |    |
       |    |    |    |    |    |    |    |    |
    0  |    |    |    |    |    |    |    |    |
       ---------------------------------------------
              Q1        Q2        Q3        Q4  

    Have fun.

    Lionel

    */

    SET NOCOUNT ON

    DECLARE @Sequence TABLE
    (
        i INT NOT NULL
    )

    DECLARE @i INT
    SET @i=0
    WHILE(@i < 100)
    BEGIN
        INSERT INTO @Sequence(i) VALUES (@i)
        SET @i = @i + 1
    END

    DECLARE @SalesResults TABLE
    (
        [Quarter] INT PRIMARY KEY CHECK([Quarter] BETWEEN 1 AND 4),
        [AmountSold] INT NOT NULL
    )

    INSERT INTO @SalesResults([Quarter], [AmountSold])
        SELECT 1, 12
    INSERT INTO @SalesResults([Quarter], [AmountSold])
        SELECT 2, 9
    INSERT INTO @SalesResults([Quarter], [AmountSold])
        SELECT 3, 15
    INSERT INTO @SalesResults([Quarter], [AmountSold])
        SELECT 4, 12

    SET NOCOUNT OFF
  • A Sql Game

    Posted Friday, December 30, 2005 5:23 PM | 10 Comments

    There seems to be computer game written in almost every language out there but I haven’t yet found one written in Transact SQL. I thought that poor old DBAs should have some form of game to play so I have written a little 3D maze game in Transact SQL. Since there is no obvious way of interacting with the game it is designed to be used from within Query Analyzer.

    You can download the SQL from the following address:
    http://www.red-gate.com/downloads/CreateTheMazeGame.txt

    Instructions on how to play:

    First run:
    EXEC spNewGame

    This creates a new game. You can then move around the maze using
    EXEC spFowards  -- Move you forwards
    EXEC spBackwards -- Move you backwards
    EXEC spLeft  -- Rotates you Left
    EXEC spRight -- Rotates you Right 

    All of these stored procedures return a single column results set that shows the view from you current position in the maze rendered in text. It works best if you have Query Analyser in view results in text mode and make sure your results are displayed in a fixed with font! Unfortunately since the maze is all drawn in text it takes a little bit of time to work out what is going on. When you run spNewGame for the first time you will find yourself looking down a corridor with much the same view you got in the old 3D games like Wolfenstein 3D. So what you are seeing is a corridor stretching out in front of you and there is a wall at the end.  You should also note that there is a slight ‘Fish Eye’ Effect as well so if the walls will look a little curved when you look at them straight on (The reason for this is that I am using a rather large Field of View which make it easy to see what is going on).  The goal of the game is to find the exit. You can tell where the exit is as the wall texture changes to the letter ‘E’ rather than ‘-‘ or ‘|’. When you reach the exit you will be given a little message to tell you that you have finished the maze.

    It is very easy to add levels. The levels themselves are just an Varchar strings. If you look at the example below The letter ‘S’ is where you start, ‘E’ is where you end, ‘1’ is a normal wall, ‘2’ is the ‘E’ wall texture use to show where the exit is an 0 is open space. You will also need to specify the width and height of your map.  The example below adds a new maze with the name ‘Long’ 

    INSERT INTO Levels (LevelName, Maze, MazeWidth, MazeHeight)
                SELECT 'Long',
                            '1111111222' +
                            '1S100012E2' +
                            '1010101101' +
                            '1010101101' +
                            '1010101101' +
                            '1010101101' +
                            '1010101101' +
                            '1010101101' +
                            '1000100001' +
                            '1111111111',
                            10, 10 

    Will add a new level called long. To try this level run:
    EXEC spNewGame 'Long' 

    I hope you have fun with this very silly piece of code and if you feel the need to make it better or even make the game fun to play please feel free to use the code in anyway you like.  

    Lionel

     

     

     

     

     

  • Sql Puzzle 4

    Posted Friday, December 16, 2005 11:35 AM | 14 Comments

    /*
    Sorry for the delay putting up this puzzle but I was going to
    post a different puzzle for this week but failed to get a solution
    for it :)

    When queuing for our food at the Christmas party, I noticed that several of us
    had already overdone the alcoholic drinks. Whilst we waited, I wondered how
    many drunk people were standing next to each other, and what was the longest
    unbroken row of these inebriated people in the queue.

    This, then is the puzzle. Below is a table that represents a queue of people. The
    value in the Position field represents their position in the queue. The FirstName
    Field holds the first name of the person. The IsDrunk
    Field is 1 if the person is drunk and 0 otherwise. Using the table below,
    construct a single query without using variables, other tables and ddl
    that returns single rows resultset which holds the most number of drunk
    people standing adjacent in a row within the queue. For the example data below
    the results should be 4, as Simon, James, Tom and Lionel are standing next to each
    other, drunk, in the queue.

    Largest Number Of Drunk People In A Row
    ---------------------------------------
    4

    */
    SET NOCOUNT ON
    DECLARE @Queue TABLE
    (
        Position INT PRIMARY KEY,
        FirstName VARCHAR(50) NOT NULL,
        IsDrunk INT NOT NULL -- 0 is not Drunk 1 is drunk
    )

    INSERT INTO @Queue(Position, FirstName, IsDrunk)
        SELECT 1, 'Nick', 1
    INSERT INTO @Queue(Position, FirstName, IsDrunk)
        SELECT 2, 'John', 0
    INSERT INTO @Queue(Position, FirstName, IsDrunk)
        SELECT 3, 'Simon', 1
    INSERT INTO @Queue(Position, FirstName, IsDrunk)
        SELECT 4, 'James', 1
    INSERT INTO @Queue(Position, FirstName, IsDrunk)
        SELECT 5, 'Tom', 1
    INSERT INTO @Queue(Position, FirstName, IsDrunk)
        SELECT 6, 'Lionel', 1
    INSERT INTO @Queue(Position, FirstName, IsDrunk)
        SELECT 7, 'Neil', 0
    INSERT INTO @Queue(Position, FirstName, IsDrunk)
        SELECT 8, 'Andras', 1
    INSERT INTO @Queue(Position, FirstName, IsDrunk)
        SELECT 9, 'Richard', 1
    INSERT INTO @Queue(Position, FirstName, IsDrunk)
        SELECT 10, 'Helen', 0

    SET NOCOUNT OFF
  • Sql Puzzle 3

    Posted Tuesday, November 22, 2005 3:50 PM | 12 Comments

    /*
    This puzzle is simple. Given the table below you have to output the words of the famous Christmas carol using a single select statement. Each line must be a separate row of the results set. I am also adding the restriction that you can not use a union statement. This is to stop cheating such as having a select statement for each line. The output should be as follows (A space between each verse would be good).

    EDIT Sorry missed the table creation code of the first post DOH!!.

    On the first day of Christmas,
    my true love sent to me
    A partridge in a pear tree.

    On the second day of Christmas,
    my true love sent to me
    Two turtle doves,
    And a partridge in a pear tree.

    On the third day of Christmas,
    my true love sent to me
    Three French hens,
    Two turtle doves,
    And a partridge in a pear tree.

    On the fourth day of Christmas,
    my true love sent to me
    Four calling birds,
    Three French hens,
    Two turtle doves,
    And a partridge in a pear tree.

    On the fifth day of Christmas,
    my true love sent to me
    Five golden rings,
    Four calling birds,
    Three French hens,
    Two turtle doves,
    And a partridge in a pear tree.

    On the sixth day of Christmas,
    my true love sent to me
    Six geese a-laying,
    Five golden rings,
    Four calling birds,
    Three French hens,
    Two turtle doves,
    And a partridge in a pear tree.

    On the seventh day of Christmas,
    my true love sent to me
    Seven swans a-swimming,
    Six geese a-laying,
    Five golden rings,
    Four calling birds,
    Three French hens,
    Two turtle doves,
    And a partridge in a pear tree.

    On the eighth day of Christmas,
    my true love sent to me
    Eight maids a-milking,
    Seven swans a-swimming,
    Six geese a-laying,
    Five golden rings,
    Four calling birds,
    Three French hens,
    Two turtle doves,
    And a partridge in a pear tree.

    On the ninth day of Christmas,
    my true love sent to me
    Nine ladies dancing,
    Eight maids a-milking,
    Seven swans a-swimming,
    Six geese a-laying,
    Five golden rings,
    Four calling birds,
    Three French hens,
    Two turtle doves,
    And a partridge in a pear tree.

    On the tenth day of Christmas,
    my true love sent to me
    Ten lords a-leaping,
    Nine ladies dancing,
    Eight maids a-milking,
    Seven swans a-swimming,
    Six geese a-laying,
    Five golden rings,
    Four calling birds,
    Three French hens,
    Two turtle doves,
    And a partridge in a pear tree.

    On the eleventh day of Christmas,
    my true love sent to me
    Eleven pipers piping,
    Ten lords a-leaping,
    Nine ladies dancing,
    Eight maids a-milking,
    Seven swans a-swimming,
    Six geese a-laying,
    Five golden rings,
    Four calling birds,
    Three French hens,
    Two turtle doves,
    And a partridge in a pear tree.

    On the twelfth day of Christmas,
    my true love sent to me
    Twelve drummers drumming,
    Eleven pipers piping,
    Ten lords a-leaping,
    Nine ladies dancing,
    Eight maids a-milking,
    Seven swans a-swimming,
    Six geese a-laying,
    Five golden rings,
    Four calling birds,
    Three French hens,
    Two turtle doves,
    And a partridge in a pear tree!

    (114 row(s) affected)

    */

    SET NOCOUNT ON

    DECLARE @Presents TABLE
    (
        InitialDayRecieved VARCHAR(50),
        Present VARCHAR(50)
    )

    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'first', 'A partridge in a pear tree'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'second', 'Two turtle doves'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'third', 'Three French hens'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'fourth', 'Four calling birds'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'fifth', 'Five golden rings'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'sixth', 'Six geese a-laying'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'seventh', 'Seven swans a-swimming'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'eighth', 'Eight maids a-milking'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'ninth', 'Nine ladies dancing'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'tenth', 'Ten lords a-leaping'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'eleventh', 'Eleven pipers piping'
    INSERT INTO @Presents(InitialDayRecieved, Present)
        SELECT 'twelfth', 'Twelve drummers drumming'

    SET NOCOUNT OFF
  • Sql Puzzle 2

    Posted Friday, November 04, 2005 4:46 PM | 2 Comments

    /*
    Todays puzzle comes from Andras who incudentally got the best
    solution so far to the last puzzle.

    We have two tables a letters table and a numbers table. The letters table
    is a letter followed by three numbers. The idea is to write a query that
    returns all the letters that have all numbers listed in the numbers table.
    This is probably best explaind in an example. so the Letters table contains

    a,1,2,3
    a,4,5,6
    a,4,5,6
    b,1,2,3
    c,1,2,3
    c,4,5,3
    d,1,9,4
    d,2,8,5
    d,3,7,6
    d,4,6,7
    e,1,2,3
    e,4,5,6
    e,4,5,6
    e,4,6,7

    The numbers table contains.
    1,2,3
    4,5,6
    4,5,6

    So for a letter to be selected it must have three entries in the letters table
    One with 1,2,3. A second with 4,5,6. A third with 4,5,6. So if there is a
    duplicate in the numbers table there must be a duplicate in the letters table.
    In the example above the result will be a and e. A is returned as it has
    exactally the three numbers following it that are in the numbers table. E is
    also returned as it also has all of the entries in the numbers table and it
    doesn't matter if there are extra ones.

    The expected result from the data bellow should be:

    Letter
    ------
    a
    e

    Happy coding :)
    */
    SET NOCOUNT ON

    DECLARE @Letters TABLE
    (
        Letter Char(1) NOT NULL,
        NumberA INT NOT NULL,
        NumberB INT NOT NULL,
        NumberC INT NOT NULL
    )
    DECLARE @Numbers TABLE
    (
        NumberA INT NOT NULL,
        NumberB INT NOT NULL,
        NumberC INT NOT NULL
    )

    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'a', 1, 2, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'a', 2, 3, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'a', 1, 2, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'a', 1, 3, 4

    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'b', 1, 2, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'b', 2, 3, 3

    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'c', 1, 2, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'c', 1, 2, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'c', 1, 2, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'c', 1, 2, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'c', 1, 2, 3

    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'd', 6, 5, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'd', 3, 2, 4
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'd', 7, 2, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'd', 1, 4, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'd', 1, 2, 3

    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'e', 1, 2, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'e', 2, 3, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'e', 1, 2, 3

    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'f', 1, 2, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'f', 2, 3, 8
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'f', 7, 3, 3
    INSERT INTO @Letters(Letter, NumberA, NumberB, NumberC)
        SELECT 'f', 1, 2, 3



    INSERT INTO @Numbers(NumberA, NumberB, NumberC)
        SELECT 1, 2, 3
    INSERT INTO @Numbers(NumberA, NumberB, NumberC)
        SELECT 1, 2, 3
    INSERT INTO @Numbers(NumberA, NumberB, NumberC)
        SELECT 2, 3, 3

    SET NOCOUNT OFF
  • A Sql Puzzle for you all

    Posted Friday, October 28, 2005 2:10 PM | 7 Comments

    /*
    To try and help everyone get a little better at sql I am setting a
    little puzzle for you all to do based on a problem that Richard had
    with the check for updates site.

    The puzzle is simple. We have a version table that holds all the version
    of all our products that we release. The version number is represented
    with four numbers a,b,c and d where a is the major version and the other
    letters represent which sub version it is. So the puzzle is to write a
    query to find the latest build for each major version. So in result from
    the data bellow should be.

    a           b           c           d          
    ----------- ----------- ----------- -----------
    1           2           2           4
    2           3           1           7
    3           2           1           5

    You are only alowed to use one SQL statment and definantly no cursers. Also
    no solutions that use any strings!!!!!. ALSO a, b, c or d could all potentally be
    Int32.MaxValue so make sure your solutions don't overflow!!!!!!!

    Email solutions to me.

    Here is some example data to get you started
    */
    DECLARE @Version TABLE
    (
        a int,
        b int,
        c int,
        d int
    )

    INSERT INTO @Version(a, b, c, d)
        SELECT 1,1,1,23
    INSERT INTO @Version(a, b, c, d)
        SELECT 1,2,1,1
    INSERT INTO @Version(a, b, c, d)
        SELECT 1,2,2,4
    INSERT INTO @Version(a, b, c, d)
        SELECT 2,1,1,1
    INSERT INTO @Version(a, b, c, d)
        SELECT 3,1,1,2
    INSERT INTO @Version(a, b, c, d)
        SELECT 2,1,2,8
    INSERT INTO @Version(a, b, c, d)
        SELECT 2,1,3,4
    INSERT INTO @Version(a, b, c, d)
        SELECT 2,2,1,2
    INSERT INTO @Version(a, b, c, d)
        SELECT 2,2,3,1
    INSERT INTO @Version(a, b, c, d)
        SELECT 2,2,4,6
    INSERT INTO @Version(a, b, c, d)
        SELECT 2,3,1,7
    INSERT INTO @Version(a, b, c, d)
        SELECT 3,2,1,5

















<November 2008>
SuMoTuWeThFrSa
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
Encouraging .NET Reflector Add-ins
 Jason Haley is well-known for the resources he's provided to developers who wish to extend Reflector's... Read more...

Using .NET Reflector Add-ins
 .NET Reflector by itself is great, but it really comes into its own with the help of some add-ins. Here... Read more...

Unique Experiences!
 You'd have thought that a unique constraint was an easy concept - Not a bit of it; it can cause a lot... Read more...

Dynamic Data Templates in ASP.NET 3.5
 Gayani gives an introduction to Dynamic Data Templates in ASP.NET 3.5 and explains how one can save a... Read more...

First Steps with .NET Reflector
 If you are new to using .NET Reflector, or you are wondering whether it would be useful to you, you'll... Read more...