Quan trọng: Vui lòng xem xét nâng cấp lên MySQL 8+ và sử dụng hàm ROW_NUMBER () được xác định và ghi lại và bỏ các bản hack cũ gắn với một phiên bản MySQL cổ có giới hạn tính năng
Bây giờ đây là một trong những hack đó:
Các câu trả lời ở đây sử dụng hầu hết các biến trong truy vấn / tất cả dường như bỏ qua thực tế là tài liệu nói (paraph cụm từ):
Đừng dựa vào các mục trong danh sách CHỌN được đánh giá theo thứ tự từ trên xuống dưới. Không gán các biến trong một mục CHỌN và sử dụng chúng trong một mục khác
Như vậy, có nguy cơ họ sẽ đưa ra câu trả lời sai, bởi vì họ thường làm một
select
(row number variable that uses partition variable),
(assign partition variable)
Nếu chúng được đánh giá từ dưới lên, số hàng sẽ ngừng hoạt động (không có phân vùng)
Vì vậy, chúng ta cần phải sử dụng một cái gì đó với một trật tự thực hiện được đảm bảo. Nhập TRƯỜNG HỢP KHI:
SELECT
t.*,
@r := CASE
WHEN col = @prevcol THEN @r + 1
WHEN (@prevcol := col) = null THEN null
ELSE 1 END AS rn
FROM
t,
(SELECT @r := 0, @prevcol := null) x
ORDER BY col
Như phác thảo ld, thứ tự gán của thuận là rất quan trọng - phải so sánh với giá trị của hàng hiện tại trước khi chúng ta gán giá trị từ hàng hiện tại (nếu không nó sẽ là giá trị col của hàng hiện tại, không phải giá trị col của hàng trước) .
Đây là cách điều này phù hợp với nhau:
KHI đầu tiên được đánh giá. Nếu col của hàng này giống với col của hàng trước thì @r được tăng lên và được trả về từ CASE. Giá trị led trả về này được lưu trữ trong @r. Đây là một tính năng của MySQL mà phép gán trả về giá trị mới của những gì được gán vào @r vào các hàng kết quả.
Đối với hàng đầu tiên trên tập kết quả, @prevcol là null (nó được khởi tạo thành null trong truy vấn con) vì vậy vị từ này là sai. Vị từ đầu tiên này cũng trả về false mỗi lần thay đổi col (hàng hiện tại khác với hàng trước). Điều này gây ra KHI thứ hai được đánh giá.
Vị từ thứ hai KHI luôn luôn sai và nó tồn tại hoàn toàn để gán giá trị mới cho @prevcol. Vì col của hàng này khác với col của hàng trước (chúng tôi biết điều này bởi vì nếu nó giống nhau, WHEN đầu tiên sẽ được sử dụng), chúng tôi phải gán giá trị mới để giữ cho thử nghiệm lần sau. Bởi vì phép gán được thực hiện và sau đó kết quả của phép gán được so sánh với null và mọi thứ tương đương với null là sai, vị từ này luôn luôn là sai. Nhưng ít nhất là đánh giá nó đã làm công việc giữ giá trị col từ hàng này, vì vậy nó có thể được đánh giá theo giá trị col của hàng tiếp theo
Bởi vì WHEN thứ hai là sai, điều đó có nghĩa là trong trường hợp cột mà chúng ta phân vùng theo (col) đã thay đổi, thì ELSE cung cấp giá trị mới cho @r, khởi động lại việc đánh số từ 1
Chúng tôi nhận được một tình huống này:
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY pcol1, pcol2, ... pcolX ORDER BY ocol1, ocol2, ... ocolX) rn
FROM
t
Có dạng chung:
SELECT
t.*,
@r := CASE
WHEN col1 = @pcol1 AND col2 = @pcol2 AND ... AND colX = @pcolX THEN @r + 1
WHEN (@pcol1 := pcol1) = null OR (@pcol2 := col2) = null OR ... OR (@pcolX := colX) = null THEN null
ELSE 1
END AS rn
FROM
t,
(SELECT @r := 0, @pcol1 := null, @pcol2 := null, ..., @pcolX := null) x
ORDER BY pcol1, pcol2, ..., pcolX, ocol1, ocol2, ..., ocolX
Chú thích:
P trong pcol có nghĩa là "phân vùng", o trong atio có nghĩa là "trật tự" - ở dạng chung tôi đã bỏ "tiền tố" từ tên biến để giảm sự lộn xộn thị giác
Các dấu ngoặc xung quanh (@pcolX := colX) = null
là quan trọng. Nếu không có họ, bạn sẽ gán null cho @pcolX và mọi thứ sẽ ngừng hoạt động
Đó là một sự thỏa hiệp rằng tập kết quả cũng phải được sắp xếp theo các cột phân vùng, cho cột trước đó so với giải quyết. Do đó, bạn không thể yêu cầu số thứ tự của mình theo một cột nhưng tập kết quả của bạn được sắp xếp theo một cột khác Bạn có thể giải quyết vấn đề này bằng các truy vấn con nhưng tôi tin rằng các tài liệu cũng nói rằng việc đặt hàng truy vấn phụ có thể bị bỏ qua trừ khi LIMIT được sử dụng và điều này có thể ảnh hưởng hiệu suất
Tôi đã không đào sâu vào nó ngoài việc kiểm tra rằng phương thức hoạt động, nhưng nếu có rủi ro thì các biến vị ngữ trong lần thứ hai KHI sẽ được tối ưu hóa (mọi thứ so với null là null / false, vậy tại sao phải chạy bài tập) và không được thực thi , nó cũng dừng lại. Điều này dường như không xảy ra theo kinh nghiệm của tôi nhưng tôi sẵn sàng chấp nhận ý kiến và đề xuất giải pháp nếu nó có thể xảy ra một cách hợp lý
Có thể là khôn ngoan khi truyền các null tạo @pcolX cho các loại cột thực tế của bạn, trong truy vấn con tạo các biến @pcolX, viz: select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)
greatest-n-per-group
để hướng dẫn bạn cho các câu hỏi tương tự.