Oggi Marco ha posto il seguente quesito sul newsgroup microsoft.public.it.sql:
Ho un tabella... con un solo campo...
Numero
---------
5
8
13
Vorrei sapere se è possibile recuperare i numeri non in uso... tramite una qualche funzione che dovrebbe restituire
Numero
-------
1
2
3
4
6
7
9
10
11
12
Di soluzioni ne esistono parecchie, ma un'idea potrebbe essere quella di scrivere una semplice User-defined function Multistatement Table-valued che accetti in input l'estremo superiore della serie numerica che vogliamo generare e che restituisca in output un result set di una sola colonna con tutti i numeri della serie partendo da 1.
A questo punto possiamo valutare un paio di query:
• La prima basata su una classica OUTER JOIN;
• La seconda che ricorre al nuovo operatore EXCEPT introdotto in SQL Server 2005.
Buttiamo giù due righe di codice:
USE tempdb;
CREATE TABLE dbo.Numeri(
Numero int NOT NULL
);
GO
CREATE FUNCTION dbo.ufn_Numbers(
@MaxNumber int
)
RETURNS @Numbers TABLE(
Number int
)
AS
BEGIN
DECLARE @idx int
SET @idx = 1
WHILE @idx <= @MaxNumber
BEGIN
INSERT @Numbers VALUES (@idx)
SET @idx = @idx + 1
END
RETURN
END
GO
INSERT dbo.Numeri VALUES(5);
INSERT dbo.Numeri VALUES(8);
INSERT dbo.Numeri VALUES(13);
/* Soluzione per SQL Server 2000/2005 */
SELECT F.Number
FROM dbo.Numeri AS N
RIGHT JOIN dbo.ufn_Numbers(12) AS F
ON N.Numero = F.Number
WHERE N.Numero IS NULL;
/* Soluzione per SQL Server 2005 */
SELECT Number
FROM dbo.ufn_Numbers(12)
EXCEPT
SELECT Numero
FROM dbo.Numeri;
/* Output:
Number
-----------
1
2
3
4
6
7
9
10
11
12
(10 row(s) affected)
*/
DROP FUNCTION dbo.ufn_Numbers;
DROP TABLE dbo.Numeri;
La prima query si limita a considerare tutte le righe della funzione dbo.ufn_Numbers, restituendo solo quelle non presenti nella tabella dbo.Numeri; la seconda restituisce tutte le righe della funzione dbo.ufn_Numbers, ad eccezione di quelle presenti nella tabella dbo.Numeri.
Per maggiori informazioni sull'operatore EXCEPT vi rimando a questo paragrafo dei Books Online.