Program Tip

MySQL은 ORDER BY에서 행 위치를 얻습니다.

programtip 2020. 10. 14. 20:52
반응형

MySQL은 ORDER BY에서 행 위치를 얻습니다.


다음 MySQL 테이블을 사용합니다.

+-----------------------------+
+ 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에서 행을 열거 할 수 있지만 단일 행에 대해 잠재적으로 큰 결과 집합을로드하는 것은 낭비적인 것 같습니다.


이것을 사용하십시오 :

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의 위치를, 다른 하나에 3의 위치를 ​​제공 할 때 둘 다 위치가 2가됩니다.


이것이 제가 생각할 수있는 유일한 방법입니다.

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

쿼리가 단순하고 반환 된 결과 집합의 크기가 잠재적으로 큰 경우이를 두 개의 쿼리로 분할 할 수 있습니다.

축소 필터링 기준이있는 첫 번째 쿼리는 해당 행의 데이터를 검색하고 두 번째 쿼리는 COUNTwith WHERE절을 사용하여 위치를 계산합니다.

예를 들어 귀하의 경우

쿼리 1 :

SELECT * FROM tbl WHERE name = 'Beta'

쿼리 2 :

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

우리는 2M 레코드가있는 테이블에서이 접근 방식을 사용하며 이것은 OMG Ponies의 접근 방식보다 확장 성이 훨씬 뛰어납니다.


I've got a very very similar issue, that's why I won't ask the same question, but I will share here what did I do, I had to use also a group by, and order by AVG. There are students, with signatures and socore, and I had to rank them (in other words, I first calc the AVG, then order them in DESC, and then finally I needed to add the position (rank for me), So I did something Very similar as the best answer here, with a little changes that adjust to my problem):

I put finally the position (rank for me) column in the external SELECT

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 

The position of a row in the table represents how many rows are "better" than the targeted row.

So, you must count those rows.

SELECT COUNT(*)+1 FROM table WHERE name<'Beta'

In case of a tie, the highest position is returned.

If you add another row with same name of "Beta" after the existing "Beta" row, then the position returned would be still 2, as they would share same place in the classification.

Hope this helps people that will search for something similar in the future, as I believe that the question owner already solved his issue.


The other answers seem too complicated for me.

Here comes an easy example, let's say you have a table with columns:

userid | points

and you want to sort the userids by points and get the row position (the "ranking" of the user), then you use:

SET @row_number = 0;

SELECT 
    (@row_number:=@row_number + 1) AS num, userid, points
FROM
    ourtable
ORDER BY points DESC

num gives you the row postion (ranking).

If you have MySQL 8.0+ then you might want to use ROW_NUMBER()


I was going through the accepted answer and it seemed bit complicated so here is the simplified version of it.

SELECT t,COUNT(*) AS position FROM t      
 WHERE name <= 'search string' ORDER BY name

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..

참고URL : https://stackoverflow.com/questions/3614666/mysql-get-row-position-in-order-by

반응형