[sql] 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의 접근 방식보다 확장 성이 훨씬 뛰어납니다.


답변

다른 답변은 너무 복잡해 보입니다.

다음은 간단한 예 입니다. 열이있는 테이블이 있다고 가정 해 보겠습니다.

userid | points

사용자 ID를 포인트별로 정렬하고 행 위치 (사용자의 “순위”)를 얻으려면 다음을 사용합니다.

SET @row_number = 0;

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

num 행 위치 (순위)를 제공합니다.

MySQL 8.0 이상이있는 경우 ROW_NUMBER () 를 사용하는 것이 좋습니다.


답변

테이블에서 행의 위치는 대상 행보다 “더 나은”행 수를 나타냅니다.

따라서 해당 행을 계산해야합니다.

SELECT COUNT (*) + 1 from tableWHERE name< ‘베타’

동점 일 경우 가장 높은 순위가 반환됩니다.

기존 “Beta”행 뒤에 “Beta”라는 이름이 같은 다른 행을 추가하면 분류에서 동일한 위치를 공유하므로 반환 된 위치는 여전히 2입니다.

질문 소유자가 이미 문제를 해결했다고 생각하므로 향후 유사한 것을 검색하는 사람들에게 도움이되기를 바랍니다.


답변

저에게는 매우 유사한 문제가 있으므로 동일한 질문을하지 않겠습니다.하지만 여기서 제가 한 일을 공유하고 AVG에서 그룹 별 및 주문을 사용해야했습니다. 서명과 소 코어가있는 학생이 있는데 순위를 매겨 야했습니다 (즉, 먼저 AVG를 계산 한 다음 DESC에서 주문한 다음 마지막으로 순위를 추가해야하므로 뭔가 매우 유사 은 AS 가장 좋은 대답 ) 내 문제에 적응 약간의 변화가 여기 :

마지막으로 position외부 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


답변

나는 받아 들여진 대답을 살펴 보았고 약간 복잡해 보였으므로 여기에 단순화 된 버전이 있습니다.

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