Logo HeaderGraphic
"... A Yankee in the Land of The Long White Cloud, Aotearoa ..."

Refactoring in SQL 

This entry won’t be much to anyone used to working with sql or refactoring or the With Clause, but sometimes I like to just walk thru how I started and how I ended when refactoring, and SQL can be refactored just like any other type of code.

I’m working on a SQL procedure where I need to be able to sort a set of items, and find the “next” one in the list.  I figured out how to do that using two statements:

DECLARE @rowIndex int;

SELECT
    @rowIndex = RowNumber + @IndexDelta
FROM (
    SELECT
        ROW_NUMBER() OVER (ORDER BY [SheetId] DESC) AS [RowNumber],
        [Uid]
    FROM
        [Sheets.SheetInfo.Functions.SheetList.Sheet.SelectAll](
            @SheetType , @CreatedBy , NULL , @LocationUid ,
            @ObserverUid , @FromSheetId , @ToSheetId , @FromDate , @ToDate
        )
    ) AS temp
WHERE [Uid] = @SheetUid


SELECT
    ISNULL([Uid],  CAST('00000000-0000-0000-0000-000000000000' AS UNIQUEIDENTIFIER))
FROM (
    SELECT
        ROW_NUMBER() OVER (ORDER BY [SheetId] DESC) AS [RowNumber],
        [Uid]
    FROM
        [Sheets.SheetInfo.Functions.SheetList.Sheet.SelectAll](
            @SheetType , @CreatedBy , NULL , @LocationUid ,
            @ObserverUid , @FromSheetId , @ToSheetId , @FromDate , @ToDate
        )
    ) AS temp
WHERE  [RowNumber] = @rowIndex

Running the above code on my humongous load test database (3.5 gig in size), takes 5 seconds.

Well next thing up, is it seems to me we could Nest the entire structure and get rid of the intermediate @rowIndex.

SELECT
    ISNULL([Uid],  CAST('00000000-0000-0000-0000-000000000000' AS UNIQUEIDENTIFIER))
FROM (
    SELECT
        ROW_NUMBER() OVER (ORDER BY [SheetId] DESC) AS [RowNumber],
        [Uid]
    FROM
        [Sheets.SheetInfo.Functions.SheetList.Sheet.SelectAll](
            @SheetType , @CreatedBy , NULL , @LocationUid ,
            @ObserverUid , @FromSheetId , @ToSheetId , @FromDate , @ToDate
        )
    ) AS temp
WHERE  [RowNumber] = (
    SELECT
        RowNumber + @IndexDelta
    FROM (
        SELECT
            ROW_NUMBER() OVER (ORDER BY [SheetId] DESC) AS [RowNumber],
            [Uid]
        FROM
            [Sheets.SheetInfo.Functions.SheetList.Sheet.SelectAll](
                @SheetType , @CreatedBy , NULL , @LocationUid ,
                @ObserverUid , @FromSheetId , @ToSheetId , @FromDate , @ToDate
            )
        ) AS temp
    WHERE [Uid] = @SheetUid
)

Well that is simplified and got rid of the intermediate int, but still it seems a little “off” and hard to read

Now as you can see, I’m using a nested from structure where one of my from clauses is to a stored procedure that takes some parameters, and that proc is used in both parts of the query, in fact the first level “from” is identical for both parts

SELECT
    ROW_NUMBER() OVER (ORDER BY [SheetId] DESC) AS [RowNumber],
    [Uid]
FROM
    [Sheets.SheetInfo.Functions.SheetList.Sheet.SelectAll](
        @SheetType , @CreatedBy , NULL , @LocationUid ,
        @ObserverUid , @FromSheetId , @ToSheetId , @FromDate , @ToDate
    )
) AS temp

Well rather then declaring this same item twice seems to me this is a good candidate for a “With” clause, and lets see if that cleans things up a bit…

WITH sheetsCte as (
    SELECT
        ROW_NUMBER() OVER (ORDER BY [SheetId] DESC) AS [RowNumber],
        [Uid]
    FROM
        [Sheets.SheetInfo.Functions.SheetList.Sheet.SelectAll](
            @SheetType , @CreatedBy , NULL , @LocationUid ,
            @ObserverUid , @FromSheetId , @ToSheetId , @FromDate , @ToDate
        )
)

SELECT
    ISNULL([Uid],  CAST('00000000-0000-0000-0000-000000000000' AS UNIQUEIDENTIFIER))
FROM
    sheetsCte
WHERE  [RowNumber] = (
    SELECT
        RowNumber + @IndexDelta
    FROM sheetsCte
    WHERE [Uid] = @SheetUid
)

and in fact that works just GREAT, reads nicely and I think a good exercise in Sql refactoring.

 
Posted on 10-Dec-09 by Matthew C. Hintzen
Bookmark this post with:        
Tags: Development, Musings and Thoughts