2010-09-01 2 views
69

С следующей таблицей MySQL:MySQL получить позицию строки в ORDER BY

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

Как я могу выбрать единственную строки и ее положение среди других строк в таблице, при сортировке по name ASC. Таким образом, если данные таблицы выглядит следующим образом, при сортировке по имени:

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

Как я мог выбрать Beta строку, получая текущую позицию этой строки? Результирующий набор я ищу будет что-то вроде этого:

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

я могу сделать простой SELECT * FROM tbl ORDER BY name ASC затем перечислить строки в PHP, но это, кажется расточительным, чтобы загрузить потенциально большой набор результатов только для одной строки.

+0

http://stackoverflow.com/questions/2520357/mysql-get-row-number-on-select –

+0

Возможный дубликат [MySQL - Получить номер строки на выберите] (http://stackoverflow.com/questions/2520357/mysql-get-row-number-on-select) – jberryman

ответ

98

Используйте это:

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' 

... чтобы получить уникальное значение позиции. Это:

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

... даст связи одинаковое значение. IE: Если на втором месте два значения, они будут иметь позицию 2, когда первый запрос даст позицию от 2 до одного из них, а 3 - к другому ...

+3

Любые комментарии к исполнению? – actual

+0

@ actual: нет ничего, что можно сказать - нет альтернативы, кроме перехода к конкуренту, который поддерживает аналитические функции (PostgreSQL, Oracle, SQL Server, DB2 ...) –

+2

@OMGPonies Просто забудьте запятую после 'position', но это идеально. – pierallard

16

Это единственный способ, которым я могу думать:

SELECT `id`, 
     (SELECT COUNT(*) FROM `table` WHERE `name` <= 'Beta') AS `position`, 
     `name` 
FROM `table` 
WHERE `name` = 'Beta' 
+1

+1 Хороший трюк ... Однако вы, вероятно, захотите использовать 'name <= 'Beta' 'вместо –

+0

yep, спасибо за исправление – zerkms

+0

Этот подход даст одинаковые значения позиции для связей. –

-7

может быть то, что вам нужно, с синтаксисом надстройкой

LIMIT

поэтому используйте

SELECT * FROM tbl ORDER BY name ASC LIMIT 1 

если вам просто нужно один ряд ..

+0

Вы неправильно читаете сообщение. Он хочет, чтобы позиция строк в наборе – Navarr

+0

не отвечала этому вопросу. Вы могли бы удалить его –

6

Если запрос прост и размер возвращаемого набора результатов потенциально большой, тогда вы можете попытаться разбить его на два запроса.

Первый запрос с критерием фильтрации с узким вниз только для получения данных этой строки, а второй запрос использует COUNT с предложением WHERE для вычисления позиции.

Например, в вашем случае

Запрос 1:

SELECT * FROM tbl WHERE name = 'Beta'

Запрос 2:

SELECT COUNT(1) FROM tbl WHERE name >= 'Beta'

Мы используем этот подход в таблице 2М записи, и это более масштабируемым, чем подход OMG Ponies.

0

Позиция строки в таблице показывает, сколько строк «лучше», чем целевая строка.

Итак, вы должны считать эти строки.

SELECT COUNT (*) + 1 ОТ table ГДЕ name < 'Бета'

В случае равенства, самое высокое положение возвращается.

Если вы добавили еще одну строку с тем же именем «Бета» после существующей строки «Бета», то возвращенная позиция будет равна 2, так как они будут разделять одно и то же место в классификации.

Надеюсь, это поможет людям, которые будут искать что-то подобное в будущем, поскольку я считаю, что владелец вопроса уже решил свою проблему.

1

У меня очень похожий вопрос, поэтому я не буду задавать один и тот же вопрос, но я расскажу, что я сделал, мне пришлось использовать и группу по заказу AVG. Есть ученики с подписями и сокровищем, и мне приходилось оценивать их (другими словами, я сначала вычисляю AVG, а затем заказываю их в DESC, а затем, наконец, мне нужно было добавить позицию (ранг для меня), поэтому я сделал что-то Очень похожего как лучшего ответа здесь, с небольшими изменениями, которые приспосабливаются к моей проблеме):

я помещал окончательно position (ранг для меня) столбца внешнего ЗЕЬЕСТА

SET @rank=0; 
SELECT @rank := @rank + 1 AS ranking, t.avg, t.name 
    FROM(SELECT avg(students_signatures.score) as avg, students.name as name 
FROM alumnos_materia 
JOIN (SELECT @rownum := 0) r 
left JOIN students ON students.id=students_signatures.id_student 
GROUP BY students.name order by avg DESC) t 
+0

Этот ответ был понятнее, чем принятый. +1 – Eric

 Смежные вопросы

  • Нет связанных вопросов^_^