views:

115

answers:

4

With the following MySQL table:

+-----------------------------+
+ id INT UNSIGNED             +
+ name VARCHAR(100)           +
+-----------------------------+

How can I select a single row AND it's position amongst the other rows in the table, when sorted by name ASC. So if the table data looks like this, when sorted by name:

+-----------------------------+
+ id | name                   +
+-----------------------------+
+  5 | Alpha                  +
+  7 | Beta                   +
+  3 | Delta                  +
+ .....                       +
+  1 | Zed                    +
+-----------------------------+

How could I select the Beta row getting the current position of that row? The result set I'm looking for would be something like this:

+-----------------------------+
+ id | position | name        +
+-----------------------------+
+  7 |        2 | Beta        +
+-----------------------------+

I can do a simple SELECT * FROM tbl ORDER BY name ASC then enumerate the rows in PHP, but it seems wasteful to load a potentially large resultset just for a single row.

+1  A: 

This is the only way that I can think of:

SELECT `id`,
       (SELECT COUNT(*) FROM `table` WHERE `name` <= 'Beta') AS `position`,
       `name`
FROM `table`
WHERE `name` = 'Beta'
zerkms
+1 Nice trick... However you'd probably want to use `name <= 'Beta'` instead
Daniel Vassallo
yep, thanks for the correction
zerkms
This approach will give the same `position` values for ties.
OMG Ponies
(Deleted my previous comment - I was wrong)... What if you add a `LIMIT 1` in there? In case of a tie, you'd be getting just one row with the last position of the tie.
Daniel Vassallo
If OP can guarantee that `name` field is unique - then there is no reason to make query more complex. If he can't - then let's wait for his result expectations for tied names.
zerkms
A: 

may be what you need is with add syntax

LIMIT

so use

SELECT * FROM tbl ORDER BY name ASC LIMIT 1

if you just need one row..

pnukeid
A: 

I'm not sure exactly what you want. If you just want the second item, you can use LIMIT:

SELECT * FROM tbl ORDER BY name ASC LIMIT 1,1
Paul Schreiber
+1  A: 

Use this:

SELECT x.id, 
       x.position,
       x.name
  FROM (SELECT t.id,
               t.name,
               @rownum := @rownum + 1 AS position
          FROM TABLE t
          JOIN (SELECT @rownum := 0) r
      ORDER BY t.name) x
 WHERE x.name = 'Beta'

...to get a unique position value. This:

SELECT t.id,
       (SELECT COUNT(*)
          FROM TABLE x
         WHERE x.name <= t.name) AS position
       t.name    
  FROM TABLE t      
 WHERE t.name = 'Beta'

...will give ties the same value. IE: If there are two values at second place, they'll both have a position of 2 when the first query will give a position of 2 to one of them, and 3 to the other...

OMG Ponies