ด้วย MySQL ฉันจะสร้างคอลัมน์ที่มีดัชนีบันทึกในตารางได้อย่างไร


100

มีวิธีใดบ้างที่ฉันจะได้รับหมายเลขแถวจริงจากแบบสอบถาม

ฉันต้องการสั่งซื้อตารางที่เรียกว่า league_girl โดยใช้ช่องที่เรียกว่า score; และส่งคืนชื่อผู้ใช้และตำแหน่งแถวจริงของชื่อผู้ใช้นั้น

ฉันต้องการจัดอันดับผู้ใช้เพื่อที่ฉันจะได้บอกได้ว่าผู้ใช้คนใดคนหนึ่งอยู่ที่ไหนเช่น Joe คือตำแหน่ง 100 จาก 200 เช่น

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

ใน 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


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

สมบูรณ์แบบใช้งานได้อย่างมีเสน่ห์และเทมเพลตสามารถใช้ซ้ำได้โดยมีการ
สืบค้น

วิธีนี้ยังใช้งานได้หากแบบสอบถามพื้นฐานของคุณใช้ GROUP BY
Dave R

4

คุณยังสามารถใช้

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

เพื่อเริ่มต้นตัวแปรตัวนับ


3
@curRowอาจยังคงมีค่าจากครั้งสุดท้ายที่คุณเรียกใช้แบบสอบถามนี้ในเซสชันปัจจุบัน
Bill Karwin

จริง แต่เฉพาะในกรณีที่คุณกำลังค้นหาอินสแตนซ์การเชื่อมต่อเดียวกันอีกครั้ง ตัวแปรภายในเครื่องจะถูกกำจัดโดยอัตโนมัติเมื่อปิดการเชื่อมต่อ
Hearth

ใช่นั่นคือสิ่งที่ฉันหมายถึงเมื่อฉันพูดว่า "ในเซสชันปัจจุบัน"
Bill Karwin

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 โดยใช้ offset และ limit สำหรับการเพจ:

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