MySQL Select Random Records
Trong bài viết này sẽ hướng dẫn một số kỹ thuật để lấy bản ghi ngẫu nhiên từ 1 bảng trong database.
Trên thực tế, sẽ có một vài trường hợp bạn sẽ phải lấy bản ghi ngẫu nhiên như là:
- Lấy ngẫu nhiên các bài viết trong blog và hiển thị lên sidebar.
- Lấy một chú thích ngẫu nhiên và hiển thị “chú thích trong ngày”.
- Lấy ngẫu nhiên các ảnh trong thư viện và sử dụng làm ảnh đại diện.
Lấy ngẫu nhiên bản ghi sử dụng ORDER BY RAND()
Trong MySQL không tích hợp sẵn lệnh để lấy ngẫu nhiên bản ghi trong bảng. Mà để thực hiện thì chúng ta phải sử dụng hàm RAND
như lệnh dưới đây:
SELECT
*
FROM
tbl
ORDER BY RAND()
LIMIT 1;
Giải thích 1 chút nhé:
- Hàm
RAND()
tạo ra một giá trị ngẫu nhiên cho mỗi dòng trong bảng. ORDER BY
sắp xếp tất cả các dòng trong bảng bằng số ngẫu nhiên được tạo bởi hàmRAND()
.LIMIT
lấy dòng đầu tiên trong kết quả trả về một cách ngẫu nhiên.
Trường hợp nếu bạn muốn lấy N
bản ghi ngẫu nhiên thì bạn chỉ cần thay đổi giá trị của LIMIT
.
SELECT
*
FROM
table
ORDER BY RAND()
LIMIT N;
Ví dụ lấy ngẫu nhiên 5 customer trong bảng customers
:
SELECT
t.customerNumber, t.customerName
FROM
customers AS t
ORDER BY RAND()
LIMIT 5;
Vì nó là ngẫu nhiên nên kết quả của bạn khi chạy query có thể là sẽ khác với trong ảnh. Không sao đâu :D.
Cách này rất tốt với bảng nhỏ, nhưng với bảng lớn thì sẽ rất chậm vì MySQL phải sắp xếp rồi mới lấy ra ngẫu nhiên. Và do đó tốc độ truy vấn sẽ phụ thuốc vào số dòng của bảng. Càng nhiều dòng thì càng tốn thời gian để tạo ra số ngẫu nhiên cho mỗi dòng.
Lấy ngẫu nhiên bản ghi sử dụng INNER JOIN
Cách này có yêu cầu là trong bảng phải có trường primary key tự tăng và không có dòng trống xen kẽ.
Truy vấn sau chỉ ra cách tạo một số ngẫu nhiên dựa vào cột primary key:
SELECT
ROUND(RAND() * ( SELECT
MAX(id)
FROM
table)) as id;
Tiếp theo chúng ta sẽ join bảng với các kết quả được trả bởi query trên:
SELECT
t.*
FROM
table AS t
JOIN
(SELECT
ROUND(RAND() * (SELECT
MAX(id)
FROM
table )) AS id
) AS x
WHERE
t.id >= x.id
LIMIT 1;
Nếu sử dụng cách này thì bạn phải thực hiện truy vấn nhiều lần để lấy nhiều hơn 1 dòng ngẫu nhiên bởi vì khi mà bạn tăng giá trị limit thì truy vấn sẽ chỉ trả lại các dòng theo tuần tự bắt đầu từ dòng được chọn một cách ngẫu nhiên.
Ví dụ lấy ngẫu nhiên 1 customer từ bảng customers
SELECT
t.customerNumber, t.customerName
FROM
customers AS t
JOIN
(SELECT
ROUND(RAND() * (SELECT
MAX(customerNumber)
FROM
customers)) AS customerNumber
) AS x
WHERE
t.customerNumber >= x.customerNumber
LIMIT 1;
Lấy giá trị ngẫu nhiên sử dụng biến
Điều kiện để dùng cách này là bảng phải có cột id
và giá trị từ 1..N và không có dòng trống nào trong khoảng đó.
- Đầu tiên, lấy số ngẫu nhiên trong khoảng 1..N.
- Sau đó chọn bản ghi dựa vào số ngẫu nhiên.
SELECT
table. *
FROM
(SELECT
ROUND(RAND() * (SELECT
MAX(id)
FROM
table)) random_num,
@num:=@num + 1
FROM
(SELECT @num:=0) AS a, table
LIMIT N) AS b,
table AS t
WHERE
b.random_num = t.id;
Chú ý là các biến người dùng tự định nghĩa là các kết nối rõ ràng. Có nghĩa là cách này không thể được sử dụng với các kết nối chung. Thêm nữa là primary key phải là kiểu integer và giá trị của nó là tuần tự mà không có chỗ gián đoạn nào xen kẽ.
Trên đây là 1 vài cách cơ bản để có thể lấy giá trị ngẫu nhiên mong muốn. Nếu bạn còn cách nào hay và tối ưu hơn thì hãy chia sẻ nhé <3