ฟังก์ชันอันดับใน MySQL


155

ฉันต้องการค้นหาอันดับของลูกค้า ที่นี่ฉันเพิ่มแบบสอบถาม SQL มาตรฐาน ANSI ที่สอดคล้องกันสำหรับความต้องการของฉัน โปรดช่วยฉันแปลงเป็น MySQL

SELECT RANK() OVER (PARTITION BY Gender ORDER BY Age) AS [Partition by Gender], 
  FirstName, 
  Age,
  Gender 
FROM Person

มีฟังก์ชั่นเพื่อค้นหาอันดับใน MySQL หรือไม่

คำตอบ:


266

ทางเลือกหนึ่งคือการใช้ตัวแปรการจัดอันดับเช่นต่อไปนี้:

SELECT    first_name,
          age,
          gender,
          @curRank := @curRank + 1 AS rank
FROM      person p, (SELECT @curRank := 0) r
ORDER BY  age;

(SELECT @curRank := 0)ส่วนช่วยให้การเริ่มต้นตัวแปรโดยไม่ต้องแยกSETคำสั่ง

กรณีทดสอบ:

CREATE TABLE person (id int, first_name varchar(20), age int, gender char(1));

INSERT INTO person VALUES (1, 'Bob', 25, 'M');
INSERT INTO person VALUES (2, 'Jane', 20, 'F');
INSERT INTO person VALUES (3, 'Jack', 30, 'M');
INSERT INTO person VALUES (4, 'Bill', 32, 'M');
INSERT INTO person VALUES (5, 'Nick', 22, 'M');
INSERT INTO person VALUES (6, 'Kathy', 18, 'F');
INSERT INTO person VALUES (7, 'Steve', 36, 'M');
INSERT INTO person VALUES (8, 'Anne', 25, 'F');

ผลลัพธ์:

+------------+------+--------+------+
| first_name | age  | gender | rank |
+------------+------+--------+------+
| Kathy      |   18 | F      |    1 |
| Jane       |   20 | F      |    2 |
| Nick       |   22 | M      |    3 |
| Bob        |   25 | M      |    4 |
| Anne       |   25 | F      |    5 |
| Jack       |   30 | M      |    6 |
| Bill       |   32 | M      |    7 |
| Steve      |   36 | M      |    8 |
+------------+------+--------+------+
8 rows in set (0.02 sec)

52
+1 สำหรับการเริ่มต้นอินไลน์แบบ devious นั่นเป็นเคล็ดลับที่สวยงาม
ชาร์ลส์

28
เขาไม่ได้ขอพาร์ทิชันหรือเปล่า? ความเข้าใจของฉันเกี่ยวกับพาร์ติชั่นคือชุดผลลัพธ์จะมีการจัดอันดับแยกกันสำหรับชายและหญิง
Jesse Dhillon

2
@Jesse: ถ้าเป็นกรณีนี้ฉันเพิ่งตอบคำถามที่คล้ายกัน: stackoverflow.com/questions/3162389/multiple-ranks-in-one-table
Daniel Vassallo

6
ถ้าฉันต้องการให้อันดับที่ 4 ถึงแอนน์และบ๊อบทั้งคู่ล่ะ?
Fahim Parkar

8
สิ่งนี้ไม่ได้ใช้ตัวอย่างจากคำถามเนื่องจากมันขาดpartition by genderส่วนของฟังก์ชันการวิเคราะห์ (ซึ่ง "ตัวเลข" ค่าอันดับต่อเพศไม่ใช่สำหรับผลลัพธ์โดยรวม)
a_horse_with_no_name

53

นี่คือโซลูชันทั่วไปที่กำหนดอันดับที่หนาแน่นบนพาร์ติชันให้กับแถว มันใช้ตัวแปรผู้ใช้:

CREATE TABLE person (
    id INT NOT NULL PRIMARY KEY,
    firstname VARCHAR(10),
    gender VARCHAR(1),
    age INT
);

INSERT INTO person (id, firstname, gender, age) VALUES
(1,  'Adams',  'M', 33),
(2,  'Matt',   'M', 31),
(3,  'Grace',  'F', 25),
(4,  'Harry',  'M', 20),
(5,  'Scott',  'M', 30),
(6,  'Sarah',  'F', 30),
(7,  'Tony',   'M', 30),
(8,  'Lucy',   'F', 27),
(9,  'Zoe',    'F', 30),
(10, 'Megan',  'F', 26),
(11, 'Emily',  'F', 20),
(12, 'Peter',  'M', 20),
(13, 'John',   'M', 21),
(14, 'Kate',   'F', 35),
(15, 'James',  'M', 32),
(16, 'Cole',   'M', 25),
(17, 'Dennis', 'M', 27),
(18, 'Smith',  'M', 35),
(19, 'Zack',   'M', 35),
(20, 'Jill',   'F', 25);

SELECT person.*, @rank := CASE
    WHEN @partval = gender AND @rankval = age THEN @rank
    WHEN @partval = gender AND (@rankval := age) IS NOT NULL THEN @rank + 1
    WHEN (@partval := gender) IS NOT NULL AND (@rankval := age) IS NOT NULL THEN 1
END AS rnk
FROM person, (SELECT @rank := NULL, @partval := NULL, @rankval := NULL) AS x
ORDER BY gender, age;

ขอให้สังเกตว่าการกำหนดตัวแปรจะถูกวางไว้ภายในการCASEแสดงออก สิ่งนี้ (ในทางทฤษฎี) จะดูแลลำดับของปัญหาการประเมิน IS NOT NULLจะถูกเพิ่มในการจัดการแปลงและระยะสั้นประเภทข้อมูลปัญหาลัดวงจร

PS: สามารถแปลงเป็นหมายเลขแถวบนพาร์ติชันได้อย่างง่ายดายโดยลบเงื่อนไขทั้งหมดที่ตรวจสอบเสมอ

| id | firstname | gender | age | rank |
|----|-----------|--------|-----|------|
| 11 | Emily     | F      | 20  | 1    |
| 20 | Jill      | F      | 25  | 2    |
| 3  | Grace     | F      | 25  | 2    |
| 10 | Megan     | F      | 26  | 3    |
| 8  | Lucy      | F      | 27  | 4    |
| 6  | Sarah     | F      | 30  | 5    |
| 9  | Zoe       | F      | 30  | 5    |
| 14 | Kate      | F      | 35  | 6    |
| 4  | Harry     | M      | 20  | 1    |
| 12 | Peter     | M      | 20  | 1    |
| 13 | John      | M      | 21  | 2    |
| 16 | Cole      | M      | 25  | 3    |
| 17 | Dennis    | M      | 27  | 4    |
| 7  | Tony      | M      | 30  | 5    |
| 5  | Scott     | M      | 30  | 5    |
| 2  | Matt      | M      | 31  | 6    |
| 15 | James     | M      | 32  | 7    |
| 1  | Adams     | M      | 33  | 8    |
| 18 | Smith     | M      | 35  | 9    |
| 19 | Zack      | M      | 35  | 9    |

การสาธิตเกี่ยวกับ db <> ซอ


2
โซลูชันนี้หรือโซลูชันของ Mukesh ควรเป็นโซลูชันที่ถูกต้อง แม้ว่าในทางเทคนิคแล้วฉันเชื่อว่าวิธีแก้ปัญหาของคุณทั้งคู่แสดงถึงการจัดอันดับที่หนาแน่นและไม่ใช่อันดับที่ปกติ นี่คือคำอธิบายที่ดีของความแตกต่าง: sqlservercurry.com/2009/04/...
modulitos

คุณสามารถแจ้งให้เราทราบได้อย่างไรว่ารหัส. php ควรเป็นอย่างไร ฉันพยายามติดตาม แต่โค้ดด้านบนไม่ทำงาน วิธีการใส่รูปแบบ. php
ผู้สร้าง

วิธีนี้ไม่ใช่วิธีที่ธรรมดามาก มันจะไม่ทำงานถ้า rank_column มีค่าเป็น 0. sqlfiddle.com/#!2/9c5dd/1
ไมค์

1
@mike เพิ่มส่วน ELSE ลงในคำสั่ง CASE:ELSE @rank_count := @rank_count + 1
Prince Odame

1
@abhash ORDER BY gender, age DESC?
Salman

52

ในขณะที่คำตอบที่ได้รับการโหวตมากที่สุดนั้นไม่ได้แบ่งพาร์ติชันคุณสามารถเข้าร่วมตัวเองเพื่อรับพาร์ทิชันทั้งหมดได้เช่นกัน:

SELECT    a.first_name,
      a.age,
      a.gender,
        count(b.age)+1 as rank
FROM  person a left join person b on a.age>b.age and a.gender=b.gender 
group by  a.first_name,
      a.age,
      a.gender

ใช้ Case

CREATE TABLE person (id int, first_name varchar(20), age int, gender char(1));

INSERT INTO person VALUES (1, 'Bob', 25, 'M');
INSERT INTO person VALUES (2, 'Jane', 20, 'F');
INSERT INTO person VALUES (3, 'Jack', 30, 'M');
INSERT INTO person VALUES (4, 'Bill', 32, 'M');
INSERT INTO person VALUES (5, 'Nick', 22, 'M');
INSERT INTO person VALUES (6, 'Kathy', 18, 'F');
INSERT INTO person VALUES (7, 'Steve', 36, 'M');
INSERT INTO person VALUES (8, 'Anne', 25, 'F');

ตอบ :

Bill    32  M   4
Bob     25  M   2
Jack    30  M   3
Nick    22  M   1
Steve   36  M   5
Anne    25  F   3
Jane    20  F   2
Kathy   18  F   1

นี่เป็นคำตอบที่ยอดเยี่ยมอย่างแม่นยำเพราะฉันต้องทำการจัดอันดับพาร์ติชัน ขอบคุณครับ!
Kim Stacks

IMO มันมีความซับซ้อนเช่นเดียวกับการเลือกย่อยในคำตอบของ @Sam Kidman: O (n ^ 2) แต่ไม่รู้ว่ามันเป็นไปได้ไหมที่จะทำได้ดีกว่าใน MySQL
xmedeko

ลองดูonlamp.com/pub/a/mysql/2007/03/29/…สำหรับการสอนที่ยอดเยี่ยมในบรรทัดเดียวกัน
ferics2

เข้าร่วมด้วยตนเองเพื่อรับอันดับ! เยี่ยมมาก ที่ล่าสุดการแก้ปัญหาโดยไม่ต้องตัวแปรและโดยไม่ต้อง MySQL 8 ฟังก์ชั่นหน้าต่าง :)
Timo

24

การปรับแต่งเวอร์ชันของ Daniel เพื่อคำนวณเปอร์เซนต์ไทล์พร้อมอันดับ นอกจากนี้คนสองคนที่มีคะแนนเท่ากันจะได้รับอันดับเดียวกัน

set @totalStudents = 0;
select count(*) into @totalStudents from marksheets;
SELECT id, score, @curRank := IF(@prevVal=score, @curRank, @studentNumber) AS rank, 
@percentile := IF(@prevVal=score, @percentile, (@totalStudents - @studentNumber + 1)/(@totalStudents)*100),
@studentNumber := @studentNumber + 1 as studentNumber, 
@prevVal:=score
FROM marksheets, (
SELECT @curRank :=0, @prevVal:=null, @studentNumber:=1, @percentile:=100
) r
ORDER BY score DESC

ผลลัพธ์ของแบบสอบถามสำหรับข้อมูลตัวอย่าง -

+----+-------+------+---------------+---------------+-----------------+
| id | score | rank | percentile    | studentNumber | @prevVal:=score |
+----+-------+------+---------------+---------------+-----------------+
| 10 |    98 |    1 | 100.000000000 |             2 |              98 |
|  5 |    95 |    2 |  90.000000000 |             3 |              95 |
|  6 |    91 |    3 |  80.000000000 |             4 |              91 |
|  2 |    91 |    3 |  80.000000000 |             5 |              91 |
|  8 |    90 |    5 |  60.000000000 |             6 |              90 |
|  1 |    90 |    5 |  60.000000000 |             7 |              90 |
|  9 |    84 |    7 |  40.000000000 |             8 |              84 |
|  3 |    83 |    8 |  30.000000000 |             9 |              83 |
|  4 |    72 |    9 |  20.000000000 |            10 |              72 |
|  7 |    60 |   10 |  10.000000000 |            11 |              60 |
+----+-------+------+---------------+---------------+-----------------+

1
แม้ว่ามันจะไม่ได้มีประสิทธิภาพดีที่สุด แต่ก็ยอดเยี่ยม!
Gaspa79

18

การผสมผสานระหว่างคำตอบของ Daniel และ Salman อย่างไรก็ตามอันดับจะไม่ให้ตามลำดับอย่างต่อเนื่องกับความสัมพันธ์ที่มีอยู่ แต่จะข้ามอันดับไปที่ถัดไป ดังนั้นจำนวนสูงสุดจะถึงจำนวนแถวเสมอ

    SELECT    first_name,
              age,
              gender,
              IF(age=@_last_age,@curRank:=@curRank,@curRank:=@_sequence) AS rank,
              @_sequence:=@_sequence+1,@_last_age:=age
    FROM      person p, (SELECT @curRank := 1, @_sequence:=1, @_last_age:=0) r
    ORDER BY  age;

สคีมาและกรณีทดสอบ:

CREATE TABLE person (id int, first_name varchar(20), age int, gender char(1));

INSERT INTO person VALUES (1, 'Bob', 25, 'M');
INSERT INTO person VALUES (2, 'Jane', 20, 'F');
INSERT INTO person VALUES (3, 'Jack', 30, 'M');
INSERT INTO person VALUES (4, 'Bill', 32, 'M');
INSERT INTO person VALUES (5, 'Nick', 22, 'M');
INSERT INTO person VALUES (6, 'Kathy', 18, 'F');
INSERT INTO person VALUES (7, 'Steve', 36, 'M');
INSERT INTO person VALUES (8, 'Anne', 25, 'F');
INSERT INTO person VALUES (9, 'Kamal', 25, 'M');
INSERT INTO person VALUES (10, 'Saman', 32, 'M');

เอาท์พุท:

+------------+------+--------+------+--------------------------+-----------------+
| first_name | age  | gender | rank | @_sequence:=@_sequence+1 | @_last_age:=age |
+------------+------+--------+------+--------------------------+-----------------+
| Kathy      |   18 | F      |    1 |                        2 |              18 |
| Jane       |   20 | F      |    2 |                        3 |              20 |
| Nick       |   22 | M      |    3 |                        4 |              22 |
| Kamal      |   25 | M      |    4 |                        5 |              25 |
| Anne       |   25 | F      |    4 |                        6 |              25 |
| Bob        |   25 | M      |    4 |                        7 |              25 |
| Jack       |   30 | M      |    7 |                        8 |              30 |
| Bill       |   32 | M      |    8 |                        9 |              32 |
| Saman      |   32 | M      |    8 |                       10 |              32 |
| Steve      |   36 | M      |   10 |                       11 |              36 |
+------------+------+--------+------+--------------------------+-----------------+

1
ฉันยังใหม่กับ MySQL แต่วิธีนี้ใช้ได้หรือไม่ ใน MySQL docs กล่าวว่า "ลำดับการประเมินผลสำหรับนิพจน์ที่เกี่ยวข้องกับตัวแปรผู้ใช้นั้นไม่ได้กำหนด" dev.mysql.com/doc/refman/5.7/en/user-variables.html
narduk

13

เริ่มต้นด้วย MySQL 8 ในที่สุดคุณสามารถใช้ฟังก์ชั่นหน้าต่างได้ใน MySQL: https://dev.mysql.com/doc/refman/8.0/en/window-functions.html

คำถามของคุณสามารถเขียนได้ในลักษณะเดียวกัน:

SELECT RANK() OVER (PARTITION BY Gender ORDER BY Age) AS `Partition by Gender`, 
  FirstName, 
  Age,
  Gender 
FROM Person

ไม่ผิดเพียง แต่ใช้ไม่ได้กับ SQL เวอร์ชันที่เก่ากว่า รวมทั้งเป็นการคัดลอกและคำถามที่ผ่านมาของเขาดังนั้นจึงไม่รู้สึกว่ามันเหมาะกับคำตอบ
newdark-it

4
@ brand-it สำหรับผู้ที่ใช้งาน MySQL 8+ คำตอบนี้มีความสำคัญเนื่องจากช่วยให้เราทราบว่า Rank พร้อมใช้งานแล้ว ถ้าฉันไม่ได้เลื่อนลงไปไกลขนาดนี้ฉันจะถือว่าคำตอบก่อนหน้านี้เป็นทางออกเดียว
Steve Smith

1
@SteveSmith จุดดีมันเป็นเรื่องดีที่มีคำตอบสำหรับผู้ใช้รุ่นใหม่ของ MYSQL
newdark-it

ใช่ฉันหมดกำลังใจโดยคำตอบมากมายจากตัวแปรผู้ใช้และบล็อคลอจิก MySQL เวอร์ชั่นใหม่ช่วยให้ทำงานได้ง่ายขึ้นด้วยฟังก์ชัน RANK () ที่มีการจัดกลุ่มภายในพาร์ติชั่น
James Bond

5

@ Sam จุดของคุณเป็นแนวความคิดที่ยอดเยี่ยม แต่ฉันคิดว่าคุณเข้าใจผิดในสิ่งที่เอกสาร MySQL กำลังพูดถึงในหน้าอ้างอิง - หรือฉันเข้าใจผิด :-) - และฉันแค่อยากจะเพิ่มสิ่งนี้ถ้าใครรู้สึกอึดอัดกับ @ คำตอบของ Daniel พวกเขาจะมั่นใจมากขึ้นหรืออย่างน้อยก็ขุดลึกลงไปอีกเล็กน้อย

คุณเห็น"@curRank := @curRank + 1 AS rank"ข้างในSELECTไม่ใช่ "คำสั่งเดียว" มันเป็นส่วน "อะตอมมิก" ของคำสั่งดังนั้นมันควรจะปลอดภัย

เอกสารที่คุณอ้างอิงไปจะแสดงตัวอย่างซึ่งตัวแปรที่ผู้ใช้กำหนดเองเหมือนกันในส่วน 2 (อะตอม) ของคำสั่งตัวอย่างเช่น "SELECT @curRank, @curRank := @curRank + 1 AS rank"ชิ้นส่วนของคำสั่งยกตัวอย่างเช่น

หนึ่งอาจโต้แย้งว่า@curRankมีการใช้สองครั้งในคำตอบของ @ Daniel: (1) "@curRank := @curRank + 1 AS rank"และ (2) "(SELECT @curRank := 0) r"แต่เนื่องจากการใช้งานที่สองเป็นส่วนหนึ่งของFROMคำสั่งฉันค่อนข้างมั่นใจว่าจะได้รับการประเมินก่อน เป็นหลักทำให้มันเป็นที่สองและก่อนหน้านี้คำสั่ง

ในความเป็นจริงบนหน้าเอกสาร MySQL เดียวกันที่คุณอ้างอิงคุณจะเห็นทางออกเดียวกันในความคิดเห็น - อาจเป็นที่ที่ @Daniel ได้รับมาจาก; ใช่ฉันรู้ว่ามันเป็นความคิดเห็น แต่มันเป็นความคิดเห็นในหน้าเอกสารอย่างเป็นทางการและมีน้ำหนัก


สิ่งนี้ไม่ได้เป็นเพียงเอกสารอ้างอิง มันเป็นเพียงการเก็งกำไร (คลุมเครือ) เช่นเดียวกับคำตอบทั้งหมดที่ใช้และการเขียนตัวแปรเดียวกันซึ่งคู่มือบอกว่าไม่ได้กำหนดไว้อย่างชัดเจนแม้ว่าคู่มือจะมีข้อความที่ไม่ช่วยเหลือมากมายสิ่งที่อาจทำงานได้ตามที่คุณคาดหวังโดยไม่ต้องบอกว่าคุณคิดว่าอะไร คำอธิบายของพฤติกรรมที่ไม่รับประกันการทำงานคือ PS ตั้งแต่ 8.0 การกำหนดตัวแปรนอกตลาดหลักทรัพย์เลิกใช้แล้ว
philipxy

4

ส่วนใหญ่แก้ปัญหาตรงไปข้างหน้าเพื่อตรวจสอบตำแหน่งของค่าที่กำหนดคือการนับจำนวนของค่าก่อนที่มัน สมมติว่าเรามีค่าต่อไปนี้:

10 20 30 30 30 40
  • 30ค่าทั้งหมดถือเป็นอันดับ 3
  • 40ค่าทั้งหมดถือเป็นอันดับ 6 (อันดับ) หรืออันดับ 4 (อันดับหนาแน่น)

ตอนนี้กลับไปที่คำถามเดิม นี่คือข้อมูลตัวอย่างบางส่วนที่จัดเรียงตามที่อธิบายไว้ใน OP (อันดับที่คาดไว้จะถูกเพิ่มทางด้านขวา):

+------+-----------+------+--------+    +------+------------+
| id   | firstname | age  | gender |    | rank | dense_rank |
+------+-----------+------+--------+    +------+------------+
|   11 | Emily     |   20 | F      |    |    1 |          1 |
|    3 | Grace     |   25 | F      |    |    2 |          2 |
|   20 | Jill      |   25 | F      |    |    2 |          2 |
|   10 | Megan     |   26 | F      |    |    4 |          3 |
|    8 | Lucy      |   27 | F      |    |    5 |          4 |
|    6 | Sarah     |   30 | F      |    |    6 |          5 |
|    9 | Zoe       |   30 | F      |    |    6 |          5 |
|   14 | Kate      |   35 | F      |    |    8 |          6 |
|    4 | Harry     |   20 | M      |    |    1 |          1 |
|   12 | Peter     |   20 | M      |    |    1 |          1 |
|   13 | John      |   21 | M      |    |    3 |          2 |
|   16 | Cole      |   25 | M      |    |    4 |          3 |
|   17 | Dennis    |   27 | M      |    |    5 |          4 |
|    5 | Scott     |   30 | M      |    |    6 |          5 |
|    7 | Tony      |   30 | M      |    |    6 |          5 |
|    2 | Matt      |   31 | M      |    |    8 |          6 |
|   15 | James     |   32 | M      |    |    9 |          7 |
|    1 | Adams     |   33 | M      |    |   10 |          8 |
|   18 | Smith     |   35 | M      |    |   11 |          9 |
|   19 | Zack      |   35 | M      |    |   11 |          9 |
+------+-----------+------+--------+    +------+------------+

ในการคำนวณRANK() OVER (PARTITION BY Gender ORDER BY Age)สำหรับSarahคุณสามารถใช้แบบสอบถามนี้:

SELECT COUNT(id) + 1 AS rank, COUNT(DISTINCT age) + 1 AS dense_rank
FROM testdata
WHERE gender = (SELECT gender FROM testdata WHERE id = 6)
AND age < (SELECT age FROM testdata WHERE id = 6)

+------+------------+
| rank | dense_rank |
+------+------------+
|    6 |          5 |
+------+------------+

ในการคำนวณRANK() OVER (PARTITION BY Gender ORDER BY Age)สำหรับแถวทั้งหมดคุณสามารถใช้แบบสอบถามนี้:

SELECT testdata.id, COUNT(lesser.id) + 1 AS rank, COUNT(DISTINCT lesser.age) + 1 AS dense_rank
FROM testdata
LEFT JOIN testdata AS lesser ON lesser.age < testdata.age AND lesser.gender = testdata.gender
GROUP BY testdata.id

และนี่คือผลลัพธ์ (เพิ่มค่าการรวมทางด้านขวา):

+------+------+------------+    +-----------+-----+--------+
| id   | rank | dense_rank |    | firstname | age | gender |
+------+------+------------+    +-----------+-----+--------+
|   11 |    1 |          1 |    | Emily     |  20 | F      |
|    3 |    2 |          2 |    | Grace     |  25 | F      |
|   20 |    2 |          2 |    | Jill      |  25 | F      |
|   10 |    4 |          3 |    | Megan     |  26 | F      |
|    8 |    5 |          4 |    | Lucy      |  27 | F      |
|    6 |    6 |          5 |    | Sarah     |  30 | F      |
|    9 |    6 |          5 |    | Zoe       |  30 | F      |
|   14 |    8 |          6 |    | Kate      |  35 | F      |
|    4 |    1 |          1 |    | Harry     |  20 | M      |
|   12 |    1 |          1 |    | Peter     |  20 | M      |
|   13 |    3 |          2 |    | John      |  21 | M      |
|   16 |    4 |          3 |    | Cole      |  25 | M      |
|   17 |    5 |          4 |    | Dennis    |  27 | M      |
|    5 |    6 |          5 |    | Scott     |  30 | M      |
|    7 |    6 |          5 |    | Tony      |  30 | M      |
|    2 |    8 |          6 |    | Matt      |  31 | M      |
|   15 |    9 |          7 |    | James     |  32 | M      |
|    1 |   10 |          8 |    | Adams     |  33 | M      |
|   18 |   11 |          9 |    | Smith     |  35 | M      |
|   19 |   11 |          9 |    | Zack      |  35 | M      |
+------+------+------------+    +-----------+-----+--------+

3

หากคุณต้องการอันดับเพียงคนเดียวคุณสามารถทำสิ่งต่อไปนี้:

SELECT COUNT(Age) + 1
 FROM PERSON
WHERE(Age < age_to_rank)

การจัดอันดับนี้สอดคล้องกับฟังก์ชั่น oracle RANK (หากคุณมีคนที่มีอายุเท่ากันพวกเขาจะได้รับอันดับเดียวกันและการจัดอันดับหลังจากนั้นไม่ต่อเนื่องกัน)

มันเร็วกว่าการใช้หนึ่งในวิธีแก้ปัญหาข้างต้นในแบบสอบถามย่อยและเลือกจากสิ่งนั้นเพื่อให้ได้อันดับของคนคนหนึ่ง

สามารถใช้เพื่อจัดอันดับทุกคน แต่ช้ากว่าโซลูชันด้านบน

SELECT
  Age AS age_var,
(
  SELECT COUNT(Age) + 1
  FROM Person
  WHERE (Age < age_var)
 ) AS rank
 FROM Person

มันอาจจะกลายเป็นมากช้ากว่าการแก้ปัญหาดังกล่าวข้างต้นเมื่อจำนวนของแถวในที่Personโต๊ะเติบโต มันO (n ^ 2)กับO (n)ช้ากว่า
xmedeko

2

เพื่อหลีกเลี่ยง " อย่างไรก็ตาม " ในคำตอบของ Erandac เมื่อรวมกับคำตอบของ Daniel และ Salman ผู้ใช้อาจใช้วิธีใดวิธีหนึ่งต่อไปนี้

SELECT customerID, myDate

  -- partition ranking works only with CTE / from MySQL 8.0 on
  , RANK() OVER (PARTITION BY customerID ORDER BY dateFrom) AS rank, 

  -- Erandac's method in combination of Daniel's and Salman's
  -- count all items in sequence, maximum reaches row count.
  , IF(customerID=@_lastRank, @_curRank:=@_curRank, @_curRank:=@_sequence+1) AS sequenceRank
  , @_sequence:=@_sequence+1 as sequenceOverAll

  -- Dense partition ranking, works also with MySQL 5.7
  -- remember to set offset values in from clause
  , IF(customerID=@_lastRank, @_nxtRank:=@_nxtRank, @_nxtRank:=@_nxtRank+1 ) AS partitionRank
  , IF(customerID=@_lastRank, @_overPart:=@_overPart+1, @_overPart:=1 ) AS partitionSequence

  , @_lastRank:=customerID
FROM myCustomers, 
  (SELECT @_curRank:=0, @_sequence:=0, @_lastRank:=0, @_nxtRank:=0, @_overPart:=0 ) r
ORDER BY customerID, myDate

การจัดอันดับพาร์ติชันในตัวแปรที่ 3 ในข้อมูลโค้ดนี้จะส่งคืนหมายเลขการจัดอันดับอย่างต่อเนื่อง สิ่งนี้จะนำไปสู่โครงสร้างข้อมูลคล้ายกับrank() over partition byผลลัพธ์ ตัวอย่างเช่นดูด้านล่าง โดยเฉพาะอย่างยิ่งpartitionSequence มักจะเริ่มต้นด้วย 1 สำหรับแต่ละ partitionRank ใหม่โดยใช้วิธีนี้:

customerID    myDate   sequenceRank (Erandac)
                          |    sequenceOverAll
                          |     |   partitionRank
                          |     |     | partitionSequence
                          |     |     |    | lastRank
... lines ommitted for clarity
40    09.11.2016 11:19    1     44    1   44    40
40    09.12.2016 12:08    1     45    1   45    40
40    09.12.2016 12:08    1     46    1   46    40
40    09.12.2016 12:11    1     47    1   47    40
40    09.12.2016 12:12    1     48    1   48    40
40    13.10.2017 16:31    1     49    1   49    40
40    15.10.2017 11:00    1     50    1   50    40
76    01.07.2015 00:24    51    51    2    1    76
77    04.08.2014 13:35    52    52    3    1    77
79    15.04.2015 20:25    53    53    4    1    79
79    24.04.2018 11:44    53    54    4    2    79
79    08.10.2018 17:37    53    55    4    3    79
117   09.07.2014 18:21    56    56    5    1   117
119   26.06.2014 13:55    57    57    6    1   119
119   02.03.2015 10:23    57    58    6    2   119
119   12.10.2015 10:16    57    59    6    3   119
119   08.04.2016 09:32    57    60    6    4   119
119   05.10.2016 12:41    57    61    6    5   119
119   05.10.2016 12:42    57    62    6    6   119
...

0
select id,first_name,gender,age,
rank() over(partition by gender order by age) rank_g
from person

CREATE TABLE person (id int, first_name varchar(20), age int, gender char(1));

INSERT INTO person VALUES (1, 'Bob', 25, 'M');
INSERT INTO person VALUES (2, 'Jane', 20, 'F');
INSERT INTO person VALUES (3, 'Jack', 30, 'M');
INSERT INTO person VALUES (4, 'Bill', 32, 'M');
INSERT INTO person VALUES (5, 'Nick', 22, 'M');
INSERT INTO person VALUES (6, 'Kathy', 18, 'F');
INSERT INTO person VALUES (7, 'Steve', 36, 'M');
INSERT INTO person VALUES (8, 'Anne', 25, 'F');
INSERT INTO person VALUES (9,'AKSH',32,'M');
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.