Brutto, ma veloce e casuale. Può diventare molto brutto molto velocemente, specialmente con l'ottimizzazione descritta di seguito, quindi assicurati di volerlo davvero in questo modo.
(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)
La prima riga appare più spesso di quanto dovrebbe
Se hai grandi spazi vuoti tra gli ID nella tabella, le righe subito dopo tali spazi avranno maggiori possibilità di essere recuperate da questa query. In alcuni casi, appariranno significativamente più spesso di quanto dovrebbero. Questo non può essere risolto in generale, ma c'è una soluzione per un caso particolare comune:quando c'è uno spazio tra 0 e il primo ID esistente in una tabella.
Invece di sottoquery (SELECT RAND()*<max_id> AS ID)
usa qualcosa come (SELECT <min_id> + RAND()*(<max_id> - <min_id>) AS ID)
Rimuovi i duplicati
La query, se utilizzata così com'è, può restituire righe duplicate. È possibile evitarlo utilizzando UNION
invece di UNION ALL
. In questo modo i duplicati verranno uniti, ma la query non garantisce più di restituire esattamente 3 righe. Puoi aggirare anche questo, recuperando più righe del necessario e limitando il risultato esterno in questo modo:
(SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
...
UNION (SELECT ... LIMIT 1)
LIMIT 3
Tuttavia, non c'è ancora alcuna garanzia che vengano recuperate 3 righe. Lo rende solo più probabile.