Saturday, May 21, 2011
Thursday, February 17, 2011
Using a SQL Table of Numbers
CustID CustName GroupListThis works well from a data-entry perspective, but from our point of view in reporting, it causes some trouble. First, filtering on these values is a bit of an issue. If we want to find everyone who is marked as a Customer, we need to use a contains operation, rather than equals. With this, we need to be sure to account for the case where one of the options is a substring of another. If one of our group options is Former Customer, we don't want it showing up in a search for Customer. This is easy enough to work around, but it is an extra step to deal with.
1 Joe Smith Customer,Reseller
2 John Doe Competitor,Prospect,Reseller
3 Jane Doe Customer,Friend
4 Guy Incognito Competitor
The larger issue is that users will often want to use these fields to group or summarize a report. In this case, the only real solution is to split the list of values for each contact, and treat them as a child table.
There are a number of approaches that will accomplish this. We can scan through the contact table, creating child records for each contact one by one. We can create a few select statements to retrieve each contact's first group, second group, etc, and then union them together. However, a simpler approach is to use a table of numbers.
A table of numbers is just that - a table containing a list of numbers. For our example, we only need a few:
numThat's it - probably the simplest table you'll ever use. With this table, splitting our value lists to create a child table is easy.
1
2
3
4
...
select cust.custid,
padr( GetWordNum( cust.grouplist, ton.num, "," ), 20 ) as OneGroup
from cust inner join ton on GetWordCount( cust.grouplist, "," ) >= ton.num
custid onegroupThis is made particularly easy by VFP's GetWordNum and GetWordCount functions, but a similar idea can be used without these functions.
1 Customer
1 Reseller
2 Competitor
2 Prospect
2 Reseller
3 Customer
3 Friend
4 Competitor
Another trick with a table of numbers is to "fill in" a range of discrete values, such as a range of dates. Consider the following table of sales totals.
dDate amountThis table might be the result of aggregating the sales records for the week of Feb. 13 - 19. Dates where there were no sales do not show up, but we might want to include them with a zero in the amount field. A table of numbers makes it simple to generate the list of dates:
02/15/2011 1500.00
02/16/2011 4000.00
02/18/2011 750.00
dStart = {^2011-02-12}
dEnd = {^2011-02-19}
nDays = dEnd - dStart
select dStart + ton.num as dDate from ton where ton.num <= nDaysWe simply outer join this to our sales table to complete our date range.select AllDates.dDate, nvl( sales.amount, cast(0 as Y) ) as amount
from ( select dStart + ton.num as dDate from ton where ton.num <= nDays ) as AllDates
left outer join sales on AllDates.dDate = sales.dDate
dDate amount
02/13/2011 0.00
02/14/2011 0.00
02/15/2011 1500.00
02/16/2011 4000.00
02/17/2011 0.00
02/18/2011 750.00
02/19/2011 0.00
Wednesday, February 16, 2011
Super Bowl Notes
The second item has to do with the endgame strategy surrounding Green Bay's field goal attempt at the end of the game. Holding a three point lead, Green Bay had fourth down from the Steelers' 5 yard line with just over 2 minutes left in the game. This is a classic situation where statisticians claim teams are routinely too conservative. Kicking the field goal hands the ball back to Pittsburgh, while going for it either wins the game with a touchdown, or pins Pittsburgh deep in their own end of the field.
That kind of analysis is not too unusual; similar arguments about 4th downs come up many times each season. However, on the Advanced NFL Stats site, an interesting addition to this argument appeared. That site has a "win probability" engine - for any given game situation, it provides the probability of each team winning, based on historical game outcomes from similar situations. For the game situation after the Green Bay field goal (~2 minutes left, in their own end of the field, down 6), the trailing team is expected to win 25% of the time. For the same situation, but with the team trailing by 3 instead of by 6, they are expected to win 21% of the time.
This looks like something along the lines of my 13 is worth more than 14 post from 2009. How can it be that teams trailing by 3 in this situation are less successful than teams trailing by more? It may be that teams trailing by 3 put too much value on reaching overtime, so they play to tie the game rather than to win it outright. When teams are further behind, they are forced to avoid this bad strategy. Also, on the other side of the ball, defenses may play differently as well, when they feel they have a safer lead. This may also be a poor strategy.
In any case, it's another interesting example of a counterintuitive statistic.
Monday, February 14, 2011
Saturday, January 22, 2011
Reading List Again
Currently Reading:
The Drunkard's Walk, Leonard Mlodinow
This is a nice non-mathematical discussion of randomness and probability. It has a good description of a few of the common counterintuitive probability questions, like the Monty Hall Problem and the Two Child Problem.
Anton, Dale Eisler
See the previous entry.
The Princeton Companion to Mathematics
Ditto.
Recently Read:
American Gods, Neil Gaiman
Great. I really enjoyed this one.
Gödel's Proof, Ernest Nagel and James Newman
Kurt Gödel's Incompleteness Theorem is a great landmark in mathematical thought. While Gödel's actual paper is quite technical, the ideas are not too difficult to understand without getting too deep into the technical details. This book is a nice explanation of Gödel's proof and its implications.
In the "To Read" Pile:
A Spark at the End of Summer, David Glen Kerr
This is the first book in the Creation Myth series. I went to school with the author, and I'm looking forward to getting into this one.
Neverwhere, Neil Gaiman
Room, Emma Donoghue
Full Dark No Stars, Stephen King
Lisey's Story, Stephen King
Shalimar the Clown, Salman Rushdie
A Mathematical Nature Walk, John Adam
Also, recently I've been reading a lot of Curious George for some reason :).
Thursday, August 19, 2010
Reading List Update
Currently Reading:
Anton, Dale Eisler
This is my uncle's third book and first novel. It's a fictionalized account of the events surrounding my grandmother's family during the Bolshevik Revolution after the first world war - Anton, the main character, is based on my great-uncle Tony. The full synopsis and other information is given on the book's website.
I'm a couple chapters in, and enjoying the writing so far. It's a bit tough for me to read, since it's very personal for me, and there are some really tragic events that happen in the story. It's going to be an interesting experience to read this.
The Princeton Companion to Mathematics
I've read a few sections here and there, which have been uniformly excellent. It's quite slow going, though, as the topics require full attention and can't really be read casually.
The Dark Tower: The Gunslinger Born
I've only read the first chapter of this, but I'm enjoying it so far.
Recently Read:
Logicomix, Apostolos Doxiadis & Christos Papadimitriou
This is a book that I almost can't believe exists - it's a graphic novel about the life of Bertrand Russell and his involvement in the development of the modern philosophy of logic and mathematics. It's difficult to describe, so I'll just link to the Amazon page.
Under the Dome, Stephen King
I thought this was one of the better recent King books, and was a quick read for a thousand-page book. It was nothing earth-shattering, but I quite enjoyed it. 4/5.
The Book of Basketball, Bill Simmons
I generally like Bill's writing style and share his sense of humour, and this book was no exception. On the other hand, I'm only a casual basketball fan, so the topic itself wasn't great for me. I'd say 5/5 for writing and 3/5 for subject matter, so I guess 4/5 overall.
In the "To Read" Pile:
Shalimar the Clown, Salman Rushdie
Godel's Proof, Ernest Nagel & James Newman
A Mathematical Nature Walk, John Adam
Monday, March 15, 2010
Chess Query Language
I think this qualifies as an obscure question. It seems simple enough to answer in principle - just get a database of games, and write something to play through each game, tracking which pieces survive. Simple enough, but a fair bit of work. Luckily there's a tool that will do this type of thing: Chess Query Language.
CQL is quite powerful, and it's pretty straightforward to set up a CQL query. For example, to answer the above question about survival rates, I started by creating a query to see how often the white queen's rook survives:
:forany Rook R
(:position :initial $Rook[a1])
(:position :terminal $Rook[a-h1-8])
That's it. The first line creates a Rook piece designator; the second and third lines specify positions that have to exist in a game for the game to match the query. Thus the query will match any game where a rook is on the a1 square in the initial game position, and that same rook is somewhere on the board in the terminal game position.
This query took about 45 minutes to run through a database of about 2.5 million games, and found that this rook survived in about 1.4 million of them. I just had this repeat for all pieces and pawns to generate the final answer.
So, I can advise that if you're ever involved in a Harry Potter-style human chess game, you should volunteer to be one of the wing pawns. Don't allow yourself to play as a knight, whatever you do.
Friday, February 12, 2010
A Few More
Thursday, February 11, 2010
Owen at 9 Months
Friday, January 15, 2010
Reading List
The Princeton Companion to Mathematics
This is a wonderful thousand-page book that would seem to have an incredibly narrow appeal. It's essentially a survey of current thinking across all mathematical disciplines, written to be as accessible as possible. The original goal for the book was that it could be handled by anyone with high school-level math, but the authors weren't able to meet this for all sections. I find this incredibly interesting, and pretty much everyone else I know would not find it interesting at all :).
Under the Dome, Stephen King
I'm a reasonably big fan of King, although I haven't read some of his more recent stuff. This one has been getting reviews in the range of good to great, and drawing comparisons to The Stand, which is a favourite of mine.
The Book of Basketball, Bill Simmons
Bill Simmons writes for ESPN; he's also known as The Sports Guy. This book is essentially just all of his opinions about basketball, including a few hundred pages ranking the best players of all time.
The Dark Tower: The Gunslinger Born
Stephen King wrote a seven-novel series called The Dark Tower over a period of about 30 years. Recently, Marvel has been publishing comics in the Dark Tower universe. This book is a collection of the first few issues.
A Mathematical Nature Walk, John Adam
I hadn't heard of this one prior to receiving it for Christmas, but it looks to be the kind of thing I like.
Thursday, January 7, 2010
Close But No Cigar
- Among all teams that finished at 9-7, the 2009 Steelers' total margin of defeat (28) was the lowest. The next closest were the 1993 Broncos (30) and the 2002 Saints (35).
- The 2009 Steelers' average margin of defeat (4.0) is the lowest among all teams that lost 7 or more games.
- Among all teams that finished at 8-8, the 2008 Chargers' total margin of defeat (34) is tied for the lowest with the 1999 Raiders.
- The 2008 Chargers' average margin of defeat (4.25) is the lowest among all teams that lost 8 or more games. The 2009 Steelers are the only team with 7 losses to have a lower average margin of defeat.
- The 16-0 2007 Patriots are a bit of a special case, but you might say that they hold the record for smallest average margin of defeat, at zero.
- The 1983 Redskins finished 14-2, and their two losses were by one point each.
- The next best average margin of defeat (2.33) was by the 2000 Titans, who finished 13-3 and whose losses were by a total of 7 points.
- The team with the worst average margin of defeat (24.7) was the 1989 Steelers. They actually made the playoffs at 9-7 (unlike this year's Steelers), but had several huge losses, including a 51-0 game against Cleveland. In the playoffs, the Steelers won their first game, and then lost to the Broncos... by 1.
Tuesday, December 29, 2009
DateTimes Through OLEDB in VFP
For some time, we've been running queries against a SQL Server database through an OLE DB connection. Recently, I came across some strange behaviour when retrieving datetime values.
In one location, the application populating the SQL database allows for an empty date value. However, SQL Server doesn't allow for an empty datetime value (though it does support a null datetime). The application handles this by using the maximum SQL Server datetime value of 9999-12-31 23:59:59.997 to represent an empty date. The data looks something like this:
This is maybe a bit unusual, but not too strange. However, when querying this data through an OLE DB connection in VFP, this is the result:
That's curious. Why is the date appearing as a blank? Doing some quick investigating on the retrieved record, both Empty(ONDATE) and IsNull(ONDATE) return false. Even more curious. What would make a datetime value display as blank, but still evaluate as not empty and not null?
Ok, let's try connecting to the database using an ODBC connection instead. Here are the results of the same query:
Curious again. The data is appearing correctly here. Something must be different in the way that OLE DB and ODBC are handling these datetime values. Let's add a couple more testing values, and then retrieve them both ways, to see if that sheds any light on the situation.


This shows what's going on. The OLE DB connection is using the milliseconds to round the value to the nearest second, while the ODBC connection is just truncating the milliseconds. The weirdness with the blank value is coming from the fact that 9999-12-31 23:59:59 is also VFP's maximum datetime value, and the rounding is forcing the value past this maximum.
I generated a VFP table using the results of the OLE DB query, and opened it with a hex editor. Sure enough, there is data in the "blank" datetime value. VFP stores a datetime value in two pieces: the date as a Julian day, and the number of milliseconds past midnight. The problem value has a number of milliseconds that evaluates to slightly more than 24 hours. The Empty and IsNull functions are correctly reporting false, based on the fact that there really is a value stored there.
All in all, this is not too much trouble to work around, since we can just use an expression with CASE or DATEADD/DATEPART to have SQL Server adjust the value for us before sending the query results. It's good to understand this behaviour though, since it will also appear in other situations where milliseconds are included in datetime values, and it will be much less noticeable that any rounding is happening.
Tuesday, November 17, 2009
Pumpkin Carving Madness
Pumpkin Carving Madness 2009 underway
Owen inspecting one of the pumpkins
My entry for this year, good for second place in the voting
Kathleen's winning entry
Saturday, October 24, 2009
Wednesday, October 21, 2009
SQL Subqueries with Null Values
We commonly use a NOT IN subquery to retrieve records that do not have a related record in another table. The common example of this type of query is to retrieve all customers that do not have any orders. Here's a simple example of a Customers table and an Orders table:
Customers OrdersThere are four customers, and two of these customers have placed orders. We can use IN and NOT IN subqueries like these:
CustID FullName OrderID CustID OrderDate
1 John Doe 1 2 1/1/2009
2 Jane Doe 2 3 1/2/2009
3 Jack Smith 3 3 1/3/2009
4 Jane Smith
select * from Customers where CustID in (select CustID from Orders)
2 Jane Doe
3 Jack Smith
select * from Customers where CustID not in (select CustID from Orders)
1 John Doe
4 Jane Smith
This is as we would expect. However, let's add a fourth record to the Orders table, with a null value for the CustID:
OrderID CustID OrderDateNow, when we run the IN query, the results are unchanged; we still get customers 2 and 3. However, when we run the NOT IN query:
4 null 1/4/2009
select * from Customers where CustID not in (select CustID from Orders)
No records returned
Why are there no records returned? Shouldn't we still be getting customers 1 and 4, since these CustIDs do not appear in the Orders table? Well, let's look at how this gets handled. The subquery generates a list of CustIDs, like this:
select * from Customers where CustID not in ( 2, 3, null )
Logically, the NOT IN is treated as a series of not equals expressions, like this:
select * from Customers where ( CustID <> 2 and CustID <> 3 and CustID <> null )
Now, we can consider how this evaluates for our customer records. For customer 1, the where clause becomes:
1 <> 2 and 1 <> 3 and 1 <> null
= true and true and null
= null
This is why record 1 doesn't appear in the result set; for records to appear, the where clause must evaluate to true, not to null.
Now that I've gone through the logic on this, it's not really correct to say that customers 1 and 4 don't have any orders. The null CustID value in the Orders table means that the customer for that order is unknown, so we can't guarantee that this order doesn't belong to customer 1 or 4.
Tuesday, August 4, 2009
Stonefield Article on SoftwareCEO
Wednesday, July 22, 2009
Stonefield Profile in the Financial Post
Prairie firm finds its markets
Monday, July 13, 2009
Stonefield Profile
Stonefield Software the little Regina company that could
Wednesday, June 17, 2009
Exposition Problems
This is an interesting idea, and I think it has applications in software development as well. The normal approach when explaining an algorithm is to just explain its steps. For any reasonably complex algorithm, it's also required to give some justification for why these steps achieve the desired result. Generally, the idea is that the student obtains enough of an understanding of the logic to produce a working version of the algorithm, and to extend it if need be.All mathematicians are familiar with the concept of an open research problem. I propose the less familiar concept of an open exposition problem. Solving an open exposition problem means explaining a mathematical subject in a way that renders it totally perspicuous. Every step should be motivated and clear; ideally, students should feel that they could have arrived at the results themselves.
That's fine, but the quoted text above goes further. It talks not only about the problem itself, but also about the motivation behind the steps of the solution, and about the student's feeling they could have constructed the solution themselves. This is something else entirely. We're now talking not just about explaining an algorithm, but explaining the process through which the algorithm was devised.
When writing code, we are always encouraged to add comments explaining how the code works. When the code needs to be maintained later, it's helpful to have these comments rather than having to work out what the code is doing. But, if someone's maintaining the code, it seems likely that they may be needing to write some similar code of their own. Maybe they need to extend this piece of code, or write a similar method in another language. In such a case, "exposition" comments might be useful as well, talking about how the code came about, other options that were rejected, and so on.
In any case, it's interesting to think about, both in terms of mathematics and software development. If nothing else, I learned the word perspicuous, and got a bit of a laugh that it was the word chosen to explain about making ideas completely clear.










