• 05 Oct 2007 /  Code

    Last week, the beta version of Ubuntu Gutsy Gibbon was released, so I decided to blow away the slightly messy installation of Feisty on my laptop, and make a clean start with the new OS.

    It’s a beta, of course, so I wasn’t expecting an entirely smooth ride. I didn’t entirely anticipate the installation crashing out or freezing repeatedly, and thus rendering my laptop unbootable, but I suppose I should know by now that my hardware isn’t particularly Linux compatible.

    Anyway, with much help from Andrew and Martin, I finally got the text-mode installer to boot using the VGA compatibility cheat codes, and 20 minutes later, I rebooted into Gutsy.

    First impressions were good - the inclusion of ntfs-3g by default is a boon for users like me with NTFS partitions who dual-boot Windows, and the graphics are all a bit shinier. We were very impressed with the speed at which my laptop suspended to RAM, too, though sadly it still doesn’t manage to resume.

    I’ll be making a serious effort to use Ubuntu more over the next couple of months - for nearly everything I do on my computer these days, I reckon it’s just as good or better than Windows XP, though undoubtedly still rough around certain edges.

    I’ll let you know how I get on. I suppose I should update the somewhat dated LaptopTestingTeam wiki page for my laptop, too.

  • 28 Jul 2007 /  Code

    Recently, I’ve been working on a new project, an update to the Magdalen College JCR Rooms Database. Doing this whilst on holiday with no internet connection certainly made me appreciate the reference panel built into Dreamweaver. However, it didn’t help me with the following problem: to simplify slightly, suppose you have a database table like so:

    +----+---------+---------+
    | id | version | name    |
    +----+---------+---------+
    |  0 |       1 | apple   |
    |  0 |       2 | apple2  |
    |  1 |       1 | orange  |
    |  1 |       2 | orange2 |
    +----+---------+---------+

    Let’s call it fruit. The primary key is the composition of the id and version fields, each group of rows with the same id being different versions of the same object’s details. Possibly not the best idea in the world, in retrospect, but it was too late now.

    What I wanted to do was get the row with maximum revision within each id, i.e. a single SQL query which would return

    +----+---------+
    | id | name    |
    +----+---------+
    |  0 | apple2  |
    |  1 | orange2 |
    +----+---------+

    Getting the maximum version number within each id is, of course, as simple as

    SELECT id, MAX(revision) from fruit GROUP BY id

    .
    Then you could do a second query like

    SELECT * FROM fruit WHERE id = '$id' AND version='$ver'

    to get the rest of each row, plugging in the maximum version from the first query and working through the rows one at a time…which is fine, except that there are 250 of them in the real thing, and that’s only going to increase.

    Methods involving multiple separate queries were out. Quite apart from the performance issues, I wanted a single query to allow me to search through the latest revisions of all rows by adding to the WHERE clause.

    After much further head-scratching, I came up with

    SELECT * FROM fruit GROUP BY id HAVING version=MAX(version)

    …which returned precisely the square root of stuff all. Initial investigations when back at an internet connection led me to blame this on the rather ancient version of MySQL doing service as development SQL server on my laptop; however, upgrading to the latest stable version didn’t help.

    What did help, though - and at last we reach the point of this rather large post - were these pages, which pointed me in the direction of this one, and told me everything I ever wanted to know about the “groupwise maximum” problem, as I discovered it was called. The solution I’ll be using, paraphrased from the examples on that last page, is

    SELECT fruit1.id, fruit1.name from fruit AS fruit1,
    (SELECT id, MAX(version) AS ver FROM fruit GROUP BY id) AS fruit2
    WHERE fruit1.id=fruit2.id
    AND fruit1.version = fruit2.ver;
    

    The bracketed expression is a sub-query, which internally creates a temporary table to match the maximum versions from. Searching through the results is just a case of adding AND fruit1.field = ‘value’ to the outer WHERE clause.

    All of which is quite enough SQL for one day, and leaves me realising I still have much to learn about it.

  • 20 May 2007 /  Code, Facebook

    Every Friday, I get emailed a big spreadsheet of dinner menus for the next week. And every Friday, I spend 25 minutes copying, pasting and typing out times to get these menus into daily events for ‘Lunch’ and ‘Dinner’ on a website powered by the Mambo CMS.

    Actually, of course, I got bored of that after the first two weeks and lashed together a PHP form to cut out most of the effort; that reduced the task to about 5 minutes’ worth. But that’s still 5 minutes of my life I’ll loose each week…until now.

    Enter Python, specifically python-excelerator and xls2list. Amazingly, it turns out some clever people have already done the hard work of getting Python to read .xls files, so all I had to do was write a parser to fish out the menus.

    After some fiddling around, it seems to do the job on test data from the last few weeks. So now all I need to do is wire it up to a special email address at one end and make it output the menus into the Mambo backend database at the other.

Bad Behavior has blocked 20 access attempts in the last 7 days.