Salve a tutti,
anni fa scrissi in Transact-SQL una "schifezza" per una richiesta di questo tipo...
una "schifezza" in quanto e' pericoloso utilizzare una funzione simile per una chiave, tanto piu' se primaria, peggio ancora (nel caso di SQL Server) se clustered...
e @migliorabile ha ragione, in quanto richiede un'operazione su differenza di insiemi... e cio' si traduce in un costrutto pesante, anche se funzionante...
al di la' di cio', considerando la nostra [dbo].[tabella] con colonna [Id] che vogliamo valorizzare con il primo intero libero maggiore di 0 e tenendo presente di potenziali gaps tra le islands di valorizzazioni, dobbiamo usare una tabella di appoggio numerica contenente la serie da 1 a N, che spesso e' gia' presente per funzionalita' anche simili...
nel caso non sia presente, possiamo utilizzare il bellissimo spunto di Itzik Ben Gan, MVP di SQL Server e geniale mente matematica, che utilizzando una serie di Common Table Expressions innestate con operazioni di cross join, genera "al volo" la nostra tabella...
utilizzando piu' CTE si puo' incrementare la cardinalita' di tale tabella di appoggio, ma oltre la presente esemplificazione si deve cambiare dominio e passare al tipo di dato bigint...
ricordo che nel caso la cardinalita' della tabella base sia gia' alta, questa operazione e' dispendiosa e, nel caso, conviene non operare "al volo" ma creare effettivamente la tabella numerica di appoggio.
DECLARE @NewId int = 0;
DECLARE @min int;
SELECT @min = MAX(p.[Id])
FROM [dbo].[tabella] p
SET @min = ISNULL(@min, 0);
SET @min += 1;
-- ottiene tabella di numeri
WITH Nbrs_4( n ) AS (
SELECT 1 UNION SELECT 0 ),
Nbrs_3( n ) AS (
SELECT 1 FROM Nbrs_4 n1 CROSS JOIN Nbrs_4 n2 ),
Nbrs_2( n ) AS (
SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2 ),
Nbrs_1( n ) AS (
SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2 ),
Nbrs_0( n ) AS (
SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2 ),
Nbrs ( n ) AS (
SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2 ),
-- scarta i numeri eccessivi
cUsed AS (
SELECT n
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY n)
FROM Nbrs
) D ( n )
WHERE n <= @min
)
-- ottiene il numero valido
SELECT @NewId = MIN(n)
FROM cUsed
LEFT JOIN [dbo].[tabella] p ON p.Id = n
WHERE p.[Id] IS NULL;
SELECT @NewId;
saluti omnia
--
Andrea