MySQL - Nhận số hàng khi chọn


181

Tôi có thể chạy câu lệnh chọn và lấy số hàng nếu các mục được sắp xếp không?

Tôi có một cái bàn như thế này:

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

Sau đó tôi có thể chạy truy vấn này để nhận số lượng đơn đặt hàng theo ID:

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

Điều này cho tôi một số lượng trong mỗi itemIDbảng như thế này:

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

Tôi cũng muốn lấy số hàng, vì vậy tôi có thể nói đó itemID=388là hàng đầu tiên, 234là thứ hai, v.v (về cơ bản là thứ hạng của các đơn hàng, không chỉ là số liệu thô). Tôi biết tôi có thể làm điều này trong Java khi tôi lấy lại kết quả, nhưng tôi đã tự hỏi liệu có cách nào để xử lý nó hoàn toàn bằng SQL không.

Cập nhật

Đặt thứ hạng sẽ thêm nó vào tập kết quả, nhưng không được sắp xếp đúng:

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
Để tham khảo trong tương lai: Nếu bạn muốn đặt hàng từ hạng 1 đến hạng 5, hãy sử dụng ORDER BY rank ASC(sắp xếp theo thứ hạng theo thứ tự ASCending). Tôi đoán đó là những gì bạn muốn nói nhưng không được sắp xếp đúng cách
BlueCacti

Câu trả lời:


179

Hãy nhìn vào điều này .

Thay đổi truy vấn của bạn thành:

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

Lựa chọn cuối cùng là số lượng của bạn.


1
Điều đó thêm thứ hạng vào tập kết quả, nhưng không đặt chúng theo thứ tự đúng - câu hỏi được cập nhật với kết quả
George

1
Hãy thử giữ ORDER BY ordercount DESC, và sau đó bọc toàn bộ truy vấn trong một truy vấn khác SELECTđể lấy mọi thứ từ cái đầu tiên, nhưng thứ tự theo cột thứ hạng (0 trong trường hợp này).
Mike Cialowicz

1
Bạn có thể cho thấy một ví dụ về điều này? Làm thế nào tôi sẽ bọc các lựa chọn?
George

9
Kiểm tra câu trả lời của swamibebop
thaddeusmt

1
@MikeCialowicz, Điều này không hoạt động . Tham khảo giải pháp của tôi hoặc giải pháp của Swamibebop để có câu trả lời đúng.
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
Cảm ơn đã làm rõ, điều này đã giải quyết vấn đề không theo thứ tự tôi đang gặp phải.
thaddeusmt

1
Cảm ơn, điều này thực sự hữu ích cho tôi :) Tôi ngạc nhiên không có cách nào đơn giản hơn để nhận được các 'chỉ mục' từ một tập kết quả ... nhưng dù sao cũng cảm ơn vì điều này rất tiện lợi.
chuột

Bạn có thể thêm một hàng thứ tư với tổng số gia tăng bằng cách thay đổi câu lệnh chọn đầu tiên trong SELECT \ @rn: = \ @ rn + 1 AS xếp hạng, itemID, ordercount, \ @tot: = \ @ tot + ordercount là tổng số. Để xác định giá trị ban đầu của \ @tot, giá trị này phải được thêm vào sau t2: (SELECT \ @tot: = 0) t3. Xóa \ trước mỗi \ @ mà tôi phải sử dụng để phá vỡ định dạng Đánh dấu nhỏ.
Jan Ehrhardt

2
Bất cứ ai có thể giải thích sự liên quan của t1t2?
Jared

2
@Jared, cú pháp MySQL chỉ cần một cái gì đó ở đó. Nó có thể là bất cứ điều gì, thậm chí xy.
Pacerier

31

Giải pháp của Swamibebop hoạt động, nhưng bằng cách tận dụng table.*cú pháp, chúng ta có thể tránh lặp lại tên cột bên trong selectvà nhận được kết quả đơn giản / ngắn hơn:

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

Vì vậy, nó sẽ cung cấp cho bạn:

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;

Bạn có tình cờ biết tại sao sử dụng @r := @r + 1trong một câu lệnh chọn hoạt động không, nhưng nếu nó trong một thủ tục được lưu trữ với declare r int; set r = 0;, nó sẽ phàn nàn (bật r := r +1)?
Dan M.

@Pacerier, thứ tự của hàng thứ hai được chọn có được đảm bảo ở đâu không? Tôi biết rằng thứ tự các hàng được trả về bởi select mà không có thứ tự theo mệnh đề không được đảm bảo ở bất cứ đâu và lựa chọn ngoài cùng chính xác là như vậy, mặc dù nó chọn từ lựa chọn theo thứ tự bên trong, vì vậy nó có thể là một ngoại lệ. Tuy nhiên, nếu không, tôi không thể thấy đây là một giải pháp chính xác vì nó sẽ có cùng một lỗ hổng với Mike của Chibu - không đảm bảo việc chọn thứ tự nào sẽ đi qua các bản ghi và đánh số chúng.
Dan M.

Bạn có biết tại sao ORDER BY không hoạt động bất cứ khi nào nó không có trong danh sách trường không? Xem kết quả của tôi: hastebin.com/aluqefunoy.rb
Mùa đông

11

Bạn có thể sử dụng các biến MySQL để làm điều đó. Một cái gì đó như thế này sẽ hoạt động (mặc dù, nó bao gồm hai truy vấn).

SELECT 0 INTO @x;

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

2
Cẩn thận, điều này sẽ không hoạt động vì order byxảy ra sau khi biến @xđược đánh giá. Hãy thử trải nghiệm bằng cách đặt hàng bằng cách sử dụng các cột khác. Cũng thử nghiệm với cả descasc. Bạn sẽ thấy rằng nhiều lần họ sẽ thất bại và lần duy nhất khi nó hoạt động, đó là do may mắn thuần túy do thứ tự "chọn" ban đầu của bạn có cùng thứ tự với thứ tự order by. Xem giải pháp của tôi và / hoặc giải pháp của Swamibebop.
Pacerier

@Pacerier bạn có chắc về điều đó không? Tôi đã mệt mỏi với truy vấn tương tự trong một ví dụ khác (về cơ bản chọn từ cột số và đánh số chúng theo thứ tự của chúng) có vẻ như nếu tôi đặt hàng theo var / row num, khi nó thay đổi thứ tự của các hàng kết quả, nhưng mỗi số có cùng một số num. Nhưng nếu tôi sắp xếp theo cột số, thì ASC/ DESCsẽ thay đổi thứ tự các số đó được đánh số (từ nhỏ nhất đến lớn nhất hoặc ngược lại). Vì vậy, có vẻ như trong trường hợp đó order byđã được đánh giá đầu tiên.
Dan M.

1

Hiện tại nó đã được tích hợp sẵn trong MySQL 8.0 và 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.