Question

I have a basic MySQL table, terms, comprised of an id and term field.

I want to create an alphabetically sorted dictionary index (in the literal sense), that would list ten 10 terms above the selected term, and 20 below it. An example of this could be found here http://www.urbandictionary.com/define.php?term=GD2&defid=3561357 where on the left column you see the current term highlighted, and a number of terms above it, and some below, all sorted alphabetically.

As we all know, MySQL doesn't support a ROW_NUMBER() or a similar function so we end up resorting to user variables and sub-selects. I also cannot create a View with user defined variables because MySQL doesn't allow that. Here's what I managed to come up with (and it works):

        SET @row_num := 0;

        SELECT
             @term_index := ordered.row_number
        FROM 
        (
            SELECT
                 @row_num := @row_num + 1 AS row_number, terms.*
            FROM
                terms
            ORDER BY
                term ASC
        ) AS ordered 
        WHERE
            ordered.term = 'example term';

        SET @row_num := 0;

        SELECT *
        FROM 
        (
            SELECT
                @row_num := @row_num + 1 AS row_number, terms.*
            FROM
                terms
            ORDER BY
                term ASC
        ) AS ordered
        WHERE
             row_number BETWEEN @term_index - 10 AND @term_index + 20

The first SELECT simply finds out the row number of our target term across the entire alphabetically sorted terms table. The second SELECT uses that information to get 10 terms above it and 20 terms below it.

I wonder if there's a way to avoid running the sub-select in the second SELECT query and instead just reference the first one aliased ordered. Is there a more efficient way of accomplishing this without having to resort to manually create a temporary table? What am I doing wrong here?

Was it helpful?

Solution

Update:

See this article in my blog for performance details:


If your term is indexed, you can just run:

SELECT  *
FROM    (
        SELECT  *
        FROM    terms
        WHERE   term <= @myterm
        ORDER BY
                term DESC
        LIMIT 10
        ) q
UNION ALL
SELECT  *
FROM    (
        SELECT  *
        FROM    terms
        WHERE   term > @myterm
        ORDER BY
                term
        LIMIT 20
        ) q
ORDER BY
        term

, which will be more efficient.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top