Xấu xí, nhưng nhanh chóng và ngẫu nhiên. Có thể trở nên rất xấu rất nhanh, đặc biệt là với cách điều chỉnh được mô tả bên dưới, vì vậy hãy đảm bảo rằng bạn thực sự muốn nó theo cách này.
(SELECT Products.ID, Products.Name
FROM Products
INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)
UNION ALL
(SELECT Products.ID, Products.Name
FROM Products
INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)
UNION ALL
(SELECT Products.ID, Products.Name
FROM Products
INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)
Hàng đầu tiên xuất hiện thường xuyên hơn bình thường
Nếu bạn có khoảng cách lớn giữa các ID trong bảng của mình, các hàng ngay sau khoảng trống như vậy sẽ có cơ hội lớn hơn được truy vấn bởi truy vấn này. Trong một số trường hợp, chúng sẽ xuất hiện thường xuyên hơn đáng kể. Điều này nói chung không thể được giải quyết, nhưng có một cách khắc phục cho một trường hợp cụ thể phổ biến:khi có khoảng cách giữa 0 và ID hiện có đầu tiên trong bảng.
Thay vì truy vấn con (SELECT RAND()*<max_id> AS ID)
sử dụng một cái gì đó như (SELECT <min_id> + RAND()*(<max_id> - <min_id>) AS ID)
Xóa các bản sao
Truy vấn, nếu được sử dụng nguyên trạng, có thể trả về các hàng trùng lặp. Có thể tránh điều đó bằng cách sử dụng UNION
thay vì UNION ALL
. Bằng cách này, các bản sao sẽ được hợp nhất, nhưng truy vấn không còn đảm bảo trả về chính xác 3 hàng. Bạn cũng có thể giải quyết vấn đề đó, bằng cách tìm nạp nhiều hàng hơn bạn cần và giới hạn kết quả bên ngoài như sau:
(SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
...
UNION (SELECT ... LIMIT 1)
LIMIT 3
Tuy nhiên, vẫn không có gì đảm bảo rằng 3 hàng sẽ được tìm nạp. Nó chỉ làm cho nó có nhiều khả năng hơn.