MySQL을 사용하여 테이블에 레코드 인덱스를 포함하는 열을 어떻게 생성 할 수 있습니까?


100

쿼리에서 실제 행 번호를 얻을 수있는 방법이 있습니까?

score라는 필드로 league_girl이라는 테이블을 주문할 수 있기를 원합니다. 사용자 이름과 해당 사용자 이름의 실제 행 위치를 반환합니다.

특정 사용자가 어디에 있는지 알 수 있도록 사용자 순위를 지정하고 싶습니다. Joe는 200 점 중 100 위입니다.

User Score Row
Joe  100    1
Bob  50     2
Bill 10     3

여기에서 몇 가지 해결책을 보았지만 대부분을 시도했지만 실제로 행 번호를 반환하는 것은 없습니다.

나는 이것을 시도했다 :

SELECT position, username, score
FROM (SELECT @row := @row + 1 AS position, username, score 
       FROM league_girl GROUP BY username ORDER BY score DESC) 

파생 된대로

...하지만 행 위치를 반환하지 않는 것 같습니다.

어떤 아이디어?


행이 파일 이름이거나 기본 키로 주문 하시겠습니까?
Sarfraz 2010-06-27

SQL에서 행 번호는 실제로 중요하지 않습니다. 해야 할 일은 자동 증가 기본 키를 테이블에 추가하는 것입니다.
simendsjo

9
기본 키는 실제 행 위치에 대해 신뢰할 수 없으므로 행 식별자가 아니어야합니다.
TheBounder

3
게다가 행 번호는 내가 정적 인 값이 아니라고 가정하는 점수의 함수이므로 자동 증분 값 (기본 키 여부)으로 만들면 의도 한 결과를 얻을 수 없습니다.
kasperjj

당신은 사용자 정의 함수에 대한 추악한을 저장 참조 할 수 있습니다 datamakessense.com/mysql-rownum-row-number-function
AdrianBR

답변:


174

다음을 시도해 볼 수 있습니다.

SELECT  l.position, 
        l.username, 
        l.score,
        @curRow := @curRow + 1 AS row_number
FROM    league_girl l
JOIN    (SELECT @curRow := 0) r;

JOIN (SELECT @curRow := 0)부분은 별도의 SET명령 없이 변수 초기화를 허용합니다 .

테스트 케이스 :

CREATE TABLE league_girl (position int, username varchar(10), score int);
INSERT INTO league_girl VALUES (1, 'a', 10);
INSERT INTO league_girl VALUES (2, 'b', 25);
INSERT INTO league_girl VALUES (3, 'c', 75);
INSERT INTO league_girl VALUES (4, 'd', 25);
INSERT INTO league_girl VALUES (5, 'e', 55);
INSERT INTO league_girl VALUES (6, 'f', 80);
INSERT INTO league_girl VALUES (7, 'g', 15);

테스트 쿼리 :

SELECT  l.position, 
        l.username, 
        l.score,
        @curRow := @curRow + 1 AS row_number
FROM    league_girl l
JOIN    (SELECT @curRow := 0) r
WHERE   l.score > 50;

결과:

+----------+----------+-------+------------+
| position | username | score | row_number |
+----------+----------+-------+------------+
|        3 | c        |    75 |          1 |
|        5 | e        |    55 |          2 |
|        6 | f        |    80 |          3 |
+----------+----------+-------+------------+
3 rows in set (0.00 sec)

19
다음 과 @curRow같이 JOIN명령문을 쉼표로 대체하여 초기화 할 수도 있습니다 .FROM league_girl l, (SELECT @curRow := 0) r
Mike

2
@ 마이크 : 사실입니다. 그리고 그것은 아마 더 깔끔 할 것입니다. 이 팁을 공유해 주셔서 감사합니다.
Daniel Vassallo

2
@smhnaji MySQL에서는 모든 "파생 된 테이블"에 이름을 지정해야합니다. 나는 그것을 "r"이라고 부르기로 결정했다. :) ...이 경우에는 거의 목적이 없지만, 일반적으로 실제 테이블 인 것처럼 파생 테이블의 속성을 참조하는 데 사용합니다.
Daniel Vassallo

20
사람들은이 행 번호가 주문이 이루어 지기 전에 계산 되므로 순서가 행 순서를 변경하면 번호가 뒤죽박죽 이 될 수 있음을 알고 있어야합니다 .
Grim ...

7
이 행 번호를 계산하는 방법이 ORDER BY있습니까?
Pierre de LESPINAY

38
SELECT @i:=@i+1 AS iterator, t.*
FROM tablename t,(SELECT @i:=0) foo

반복자 열이 10 진수가 아닌 정수가되도록이를 수행하는 방법이 있습니까?
kraftydevil

7

내가 사용한 템플릿의 구조는 다음과 같습니다.

  select
          /*this is a row number counter*/
          ( select @rownum := @rownum + 1 from ( select @rownum := 0 ) d2 ) 
          as rownumber,
          d3.*
  from 
  ( select d1.* from table_name d1 ) d3

그리고 여기 내 작업 코드가 있습니다.

select     
           ( select @rownum := @rownum + 1 from ( select @rownum := 0 ) d2 ) 
           as rownumber,
           d3.*
from
(   select     year( d1.date ), month( d1.date ), count( d1.id )
    from       maindatabase d1
    where      ( ( d1.date >= '2013-01-01' ) and ( d1.date <= '2014-12-31' ) )
    group by   YEAR( d1.date ), MONTH( d1.date ) ) d3

완벽하게는, 매력과 템플릿 등의 작품을 매개 변수로 하위 쿼리로 재사용 할 수 있습니다 ..
Zavael

이 솔루션은 기본 쿼리가 GROUP BY를 사용하는 경우에도 작동합니다
Dave R

4

당신은 또한 사용할 수 있습니다

SELECT @curRow := ifnull(@curRow,0) + 1 Row, ...

카운터 변수를 초기화합니다.


3
@curRow현재 세션에서이 쿼리를 마지막으로 실행 한 값이 여전히있을 수 있습니다.
Bill Karwin

사실이지만 동일한 연결 인스턴스에서 다시 쿼리하는 경우에만 해당됩니다. 연결이 종료되면 지역 변수가 자동으로 삭제됩니다.
Hearth

네, 그것이 제가 "현재 세션에서"라고 말했을 때의 의미입니다.
Bill Karwin 2014 년

3

MySQL이이를 지원한다고 가정하면 표준 SQL 하위 쿼리를 사용하여 쉽게 수행 할 수 있습니다.

select 
    (count(*) from league_girl l1 where l2.score > l1.score and l1.id <> l2.id) as position,
    username,
    score
from league_girl l2
order by score;

많은 양의 결과가 표시되는 경우 약간 느리며 대신 자체 조인으로 전환하는 것이 좋습니다.


3

필드 점수로 정렬 한 후 특정 사용자의 위치 만 알고 싶다면 테이블에서 필드 점수가 현재 사용자 점수보다 높은 모든 행을 선택하기 만하면됩니다. 그리고 반환 된 행 번호 + 1을 사용하여 현재 사용자의 위치를 ​​알 수 있습니다.

테이블이 league_girl이고 기본 필드가 이라고 가정하면 id다음을 사용할 수 있습니다.

SELECT count(id) + 1 as rank from league_girl where score > <your_user_score>

0

원래 답변이 매우 도움이되었지만 삽입 한 행 번호를 기반으로 특정 행 집합을 가져오고 싶었습니다. 따라서 삽입 한 행 번호를 참조 할 수 있도록 전체 원래 답변을 하위 쿼리에 래핑했습니다.

SELECT * FROM 
( 
    SELECT *, @curRow := @curRow + 1 AS "row_number"
    FROM db.tableName, (SELECT @curRow := 0) r
) as temp
WHERE temp.row_number BETWEEN 1 and 10;

하위 쿼리에 하위 쿼리를 사용하는 것은 그다지 효율적이지 않으므로 SQL 서버가이 쿼리를 처리하도록하거나 전체 테이블을 가져 와서 응용 프로그램 / 웹 서버가 해당 행을 처리하도록하여 더 나은 결과를 얻을 수 있는지 테스트 해 볼 가치가 있습니다. .

개인적으로 내 SQL 서버는 지나치게 바쁘지 않으므로 중첩 된 하위 쿼리를 처리하는 것이 바람직했습니다.


0

나는 OP가 mysql대답을 요구하고 있다는 것을 알고 있지만 다른 대답이 나를 위해 작동하지 않는다는 것을 알았 기 때문에,

  • 그들 대부분은 order by
  • 또는 그들은 단순히 매우 비효율적이며 뚱뚱한 테이블에 대해 쿼리를 매우 느리게 만듭니다.

따라서 저와 같은 다른 사람들을 위해 시간을 절약하려면 데이터베이스에서 검색 한 후 행을 인덱싱하십시오.

PHP의 예 :

$users = UserRepository::loadAllUsersAndSortByScore();

foreach($users as $index=>&$user){
    $user['rank'] = $index+1;
}

페이징을 위해 오프셋 및 제한을 사용하는 PHP의 예 :

$limit = 20; //page size
$offset = 3; //page number

$users = UserRepository::loadAllUsersAndSortByScore();

foreach($users as $index=>&$user){
    $user['rank'] = $index+1+($limit*($offset-1));
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.