MySQL - รับหมายเลขแถวที่เลือก


181

ฉันสามารถรันคำสั่ง select และรับหมายเลขแถวได้หรือไม่หากรายการเรียงลำดับ?

ฉันมีโต๊ะแบบนี้:

mysql> describe orders;
+-------------+---------------------+------+-----+---------+----------------+
| Field       | Type                | Null | Key | Default | Extra          |
+-------------+---------------------+------+-----+---------+----------------+
| orderID     | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| itemID      | bigint(20) unsigned | NO   |     | NULL    |                |
+-------------+---------------------+------+-----+---------+----------------+

ฉันสามารถเรียกใช้แบบสอบถามนี้เพื่อรับจำนวนการสั่งซื้อตาม ID:

SELECT itemID, COUNT(*) as ordercount
FROM orders
GROUP BY itemID ORDER BY ordercount DESC;

สิ่งนี้ทำให้ฉันนับแต่ละคนitemIDในตารางแบบนี้:

+--------+------------+
| itemID | ordercount |
+--------+------------+
|    388 |          3 |
|    234 |          2 |
|   3432 |          1 |
|    693 |          1 |
|   3459 |          1 |
+--------+------------+

ฉันต้องการรับหมายเลขแถวด้วยดังนั้นฉันจึงบอกได้ว่านั่นitemID=388คือแถวแรก234คือที่สองเป็นต้น (โดยพื้นฐานแล้วการจัดอันดับของคำสั่งไม่ใช่เพียงการนับจำนวนดิบ) ฉันรู้ว่าฉันสามารถทำเช่นนี้ใน Java เมื่อฉันได้รับผลกลับ แต่ฉันสงสัยว่ามีวิธีการจัดการอย่างหมดจดใน SQL

ปรับปรุง

การตั้งค่าอันดับจะเพิ่มเข้าไปในชุดผลลัพธ์ แต่สั่งไม่ถูกต้อง:

mysql> SET @rank=0;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @rank:=@rank+1 AS rank, itemID, COUNT(*) as ordercount
    -> FROM orders
    -> GROUP BY itemID ORDER BY rank DESC;
+------+--------+------------+
| rank | itemID | ordercount |
+------+--------+------------+
|    5 |   3459 |          1 |
|    4 |    234 |          2 |
|    3 |    693 |          1 |
|    2 |   3432 |          1 |
|    1 |    388 |          3 |
+------+--------+------------+
5 rows in set (0.00 sec)

1
สำหรับการอ้างอิงในอนาคต: หากคุณต้องการสั่งซื้อจากอันดับ 1 ถึงอันดับ 5 ให้ใช้ORDER BY rank ASC(เรียงลำดับตามอันดับในลำดับ ASCending) ฉันเดาว่าเป็นสิ่งที่คุณหมายถึงแต่ไม่ได้รับคำสั่งอย่างถูกต้อง
BlueCacti

สำเนาที่เป็นไปได้ของROW_NUMBER () ใน MySQL
Ciro Santilli 法轮功冠状病六四事件法轮功

คำตอบ:


179

ลองดูที่นี้

เปลี่ยนคำถามของคุณเป็น:

SET @rank=0;
SELECT @rank:=@rank+1 AS rank, itemID, COUNT(*) as ordercount
  FROM orders
  GROUP BY itemID
  ORDER BY ordercount DESC;
SELECT @rank;

ตัวเลือกสุดท้ายคือการนับของคุณ


1
ที่เพิ่มอันดับให้กับชุดผลลัพธ์ แต่ไม่ได้จัดเรียงไว้ในลำดับที่ถูกต้อง - คำถามที่ปรับปรุงแล้วพร้อมผลลัพธ์
George

1
ลองรักษาตัวORDER BY ordercount DESCแล้วรวมคำทั้งหมดไว้ในอีกอันหนึ่งSELECTซึ่งรับทุกอย่างจากอันแรก แต่เรียงลำดับตามคอลัมน์อันดับ (0 ในกรณีนี้)
Mike Cialowicz

1
คุณสามารถแสดงตัวอย่างของสิ่งนี้ได้ไหม ฉันจะห่อสิ่งที่เลือกได้อย่างไร
จอร์จ

9
ตรวจสอบคำตอบของ swamibebop
thaddeusmt

1
@MikeCialowicz นี้ไม่ได้ทำงาน อ้างถึงโซลูชันของฉันหรือโซลูชันของ Swamibebop สำหรับคำตอบที่ถูกต้อง
Pacerier

178
SELECT @rn:=@rn+1 AS rank, itemID, ordercount
FROM (
  SELECT itemID, COUNT(*) AS ordercount
  FROM orders
  GROUP BY itemID
  ORDER BY ordercount DESC
) t1, (SELECT @rn:=0) t2;

1
ขอบคุณสำหรับการชี้แจงสิ่งนี้แก้ไขปัญหาที่เกิดขึ้นตามลำดับที่ฉันมี
thaddeusmt

1
ขอบคุณนี่มีประโยชน์จริง ๆ สำหรับฉัน :) ฉันรู้สึกประหลาดใจที่ไม่มีวิธีที่ง่ายกว่านี้ในการรับ 'ดัชนี' จากชุดผลลัพธ์ ... แต่อย่างไรก็ตามขอบคุณที่มันมีประโยชน์
หนู

คุณสามารถเพิ่มแถวที่สี่ด้วยผลรวมที่เพิ่มขึ้นโดยเปลี่ยนคำสั่ง select แรกใน SELECT \ @rn: = \ @ rn + 1 AS อันดับ, itemID, ordercount, \ @tot: = \ @ tot + ordercount เป็น totalcount ในการกำหนดค่าเริ่มต้นของ \ @tot สิ่งนี้ควรเพิ่มหลังจาก t2: (SELECT \ @tot: = 0) t3 ลบ \ ก่อนทุก \ @ ซึ่งฉันต้องใช้เพื่อหลีกเลี่ยงการจัดรูปแบบ mini-Markdown
Jan Ehrhardt

2
ทุกคนสามารถอธิบายความเกี่ยวข้องของt1และได้t2หรือไม่
Jared

2
@ Jared, MySQL ไวยากรณ์เพียงต้องการสิ่งที่จะมี มันสามารถเป็นอะไรก็ได้แม้และx y
Pacerier

31

โซลูชันของ Swamibebop ทำงานได้ แต่ด้วยการใช้ประโยชน์จากtable.*ไวยากรณ์เราสามารถหลีกเลี่ยงการซ้ำชื่อคอลัมน์ของ Inner selectและรับผลลัพธ์ที่ง่ายขึ้น / สั้นลง:

SELECT @r := @r+1 , 
       z.* 
FROM(/* your original select statement goes in here */)z, 
(SELECT @r:=0)y;

ดังนั้นจะให้:

SELECT @r := @r+1 , 
       z.* 
FROM(
     SELECT itemID, 
     count(*) AS ordercount
     FROM orders
     GROUP BY itemID
     ORDER BY ordercount DESC
    )z,
    (SELECT @r:=0)y;

คุณโดยบังเอิญรู้ไหมว่าทำไมการใช้@r := @r + 1คำสั่ง select จึงใช้งานได้ แต่ถ้ามันอยู่ในขั้นตอนการจัดเก็บด้วยdeclare r int; set r = 0;มันจะบ่น (เปิดr := r +1)?
Dan M.

@Pacerier ลำดับของแถวที่สองคือตัวเลือกที่รับประกันได้ที่ไหน? ฉันรู้ว่าลำดับของแถวที่ถูกส่งคืนโดยตัวเลือกที่ไม่มีลำดับตามข้อไม่รับประกันที่ใดก็ได้และตัวเลือกที่อยู่ด้านนอกสุดนั้นคือสิ่งนั้นแม้ว่ามันจะเลือกจากตัวเลือกที่เรียงลำดับภายในดังนั้นมันอาจเป็นข้อยกเว้น อย่างไรก็ตามหากไม่เป็นเช่นนั้นฉันไม่สามารถเห็นได้ว่านี่เป็นวิธีแก้ปัญหาที่ถูกต้องเพราะจะมีข้อบกพร่องเช่นเดียวกับ Mike's ของ Chibu ไม่มีการรับประกันว่าการเลือกคำสั่งใดจะผ่านบันทึกและกำหนดหมายเลข
Dan M.

คุณมีความคิดว่าทำไม ORDER BY ไม่ทำงานเมื่อใดก็ตามที่ไม่อยู่ในรายการเขตข้อมูล ดูผลลัพธ์ของฉัน: hastebin.com/aluqefunoy.rb
ฤดูหนาว

11

คุณสามารถใช้ตัวแปร MySQL เพื่อทำมันได้ บางสิ่งเช่นนี้ควรใช้งานได้ (แม้ว่าจะประกอบด้วยสองแบบสอบถาม)

SELECT 0 INTO @x;

SELECT itemID, 
       COUNT(*) AS ordercount, 
       (@x:=@x+1) AS rownumber 
FROM orders 
GROUP BY itemID 
ORDER BY ordercount DESC; 

2
ระวังสิ่งนี้จะไม่ทำงานเพราะorder byเกิดขึ้นหลังจาก@xประเมินตัวแปรแล้ว ลองทำการทดลองโดยการสั่งซื้อโดยใช้คอลัมน์อื่น นอกจากนี้ยังมีการทดสอบกับทั้งสองและdesc ascคุณจะเห็นว่าหลายครั้งที่พวกเขาจะล้มเหลวและครั้งเท่านั้นเมื่อมันทำงานมันเป็นโดยโชคบริสุทธิ์เนื่องจากคำสั่งของเดิมของคุณ "เลือก" order byที่มีการสั่งซื้อเช่นเดียวกับคำสั่งของ ดูโซลูชันของฉันและ / หรือโซลูชันของ Swamibebop
Pacerier

@Pierier คุณแน่ใจเกี่ยวกับที่? ฉันเบื่อแบบสอบถามที่คล้ายกันในตัวอย่างที่แตกต่างกัน (โดยทั่วไปเลือกจากคอลัมน์ของตัวเลขและจำนวนพวกเขาตามคำสั่งของพวกเขา) ที่ดูเหมือนว่าถ้าฉันสั่งโดย var / row NUM เมื่อเปลี่ยนลำดับของแถวผลลัพธ์ แต่แต่ละหมายเลขมีจำนวนแถวเดียวกัน แต่ถ้าฉันเรียงตามคอลัมน์ตัวเลขดังนั้นASC/ DESCจะเปลี่ยนลำดับที่หมายเลขเหล่านั้น (จากน้อยที่สุดเป็นใหญ่ที่สุดหรือกลับกัน) ดังนั้นดูเหมือนว่าในกรณีorder byนั้นจะถูกประเมินก่อน
Dan M.

1

ตอนนี้สร้างขึ้นใน MySQL 8.0 และ MariaDB 10.2:

SELECT
  itemID, COUNT(*) as ordercount,
  ROW_NUMBER OVER (PARTITION BY itemID ORDER BY rank DESC) as rank
FROM orders
GROUP BY itemID ORDER BY rank DESC
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.