Qui di seguito ho voluto riportare due esempi per l'estrazione di numeri casuali da una tabella.
Il primo esempio recupera semplicemente un valore random, mentre il secondo estrae una serie di numeri, tipo estrazione dell'otto, che devono sì essere casuali, ma anche non ripetibili.
Primo esempio:
Potrebbe capitare di voler estrarre da una tabella un record a caso, per esempio per visuallizare una frase di benvenuto sulla home del proprio sito.
Una delle possibili soluzioni potrebbe essere quella riportata qui di seguito:
-- Definisco la tabella myTable
CREATE TABLE myTable
(
Numero SMALLINT NOT NULL
) ON [PRIMARY]
GO
-- La popolo
SET NOCOUNT ON
DECLARE @x AS INT
SELECT @x = 1
WHILE not @x > 90
BEGIN
INSERT dbo.myTable VALUES(@x)
SELECT @X = @X + 1
END
SET NOCOUNT OFF
GO
--Estraggo un solo numero
DECLARE @myNumero AS SMALLINT
SELECT @myNumero = rand() * (select max(numero) from myTable)
SELECT TOP 1 * FROM myTable WHERE Numero >= @myNumero
GO
--Elimino le tabelle d'appoggio
DROP TABLE myTable
Attenzione che se i valori di Numero non fossero sequenziali, ad esempio 10,20,30 l'istruzione "
rand() * (select max(numero) from myTable)" avrebbe restituito un numero casuale tra 0 e 30; se fosse uscito ad esempio 15 non avremmo avuto nessuna occorrenza nella tabella e nessun valore restituito. Impostando, però,
Numero >= @myNumero il valore restituito sarebbe stato 20!
Secondo esempio: estrazioni dell'otto.
Qualche problema in più lo incontriamo qualora la nostra tabelle fosse usata per simulare, ad esempio, le estrazioni dell'otto.
Qui il procedimento diventa un po' più complesso, ma non impossibile.
-- Definisco la tabella myTable
CREATE TABLE myTable
(
Numero SMALLINT NOT NULL
) ON [PRIMARY]
GO
-- La popolo
SET NOCOUNT ON
DECLARE @x AS INT
SELECT @x = 1
WHILE not @x > 90
BEGIN
INSERT dbo.myTable VALUES(@x)
SELECT @X = @X + 1
END
SET NOCOUNT OFF
GO
-- Creo una tabella di appoggio per memorizzare i numeri estratti
CREATE TABLE myEstratti
(
Numero SMALLINT NOT NULL
) ON [PRIMARY]
GO
-- Imposto il numero di valori che voglio estrarre dalla tabella
-- NB. Ovviamente non devono essere superiori al numero delle righe contenute
-- altrimenti andrebbe in loop.
DECLARE @numEstratti AS int
SELECT @numEstratti = 1
WHILE NOT @numEstratti > 5
BEGIN
-- Recupero all'interno della tabella una riga in modo casuale
-- incrociando i valori con la tabella delle estrazioni in modo
-- da non avere doppioni
DECLARE @myNumero as int;
SELECT @myNumero = rand() * (
SELECT count(a.numero)
FROM myTable A
LEFT JOIN myEstratti B on a.Numero = B.numero
WHERE b.numero is null
);
--Creo una Common Table Expression
WITH getRow(RowNumber, Numero) AS
(
SELECT RowNumber = ROW_NUMBER() OVER (ORDER BY A.Numero),
A.Numero
FROM myTable A
LEFT JOIN myEstratti B on a.Numero = B.numero
WHERE b.numero is null
)
-- Aggiungo il valore estratta alla tabella di supporto
INSERT INTO myEstratti (Numero)
SELECT Numero
FROM getrow
WHERE Rownumber = @myNumero
--Incremento il contatore
SELECT @numEstratti = @numEstratti+ 1
END
-- A questo punto posso visualizzare i valori ricavati
SELECT * FROM myEstratti ORDER BY Numero
-- Elimino le tabelle d'appoggio
DROP TABLE myTable
DROP TABLE myEstratti