Query per trovare primo numero libero

di il
5 risposte

Query per trovare primo numero libero

Buonasera a tutto il forum.
Ho un poblema con una query che non riesco a risolvere.
Cerco di spiegare brevemente la situazione:
Ho una tabella "Tab_Ingressi" (può essere Access o SQL Server), con un campo numerico "ID_Code", questo campo è una chiave di ricerca, per cui deve essere univoco.
Quando memorizzo dei record in questa tabella, l'ID_Code deve partire da 1 in avanti.
Ovviamente da questa tabella posso eliminare righe con sequenza a caso, per cui vorrei che alla primo inserimento che devo fare, la query mi ritornasse il primo ID_Code libero (sempre partendo da 1)
es:
ID_Code
1
2
3
4

se inserisco la query deve darmi il valore 5
elimino il 3 (la query deve ritornarmi 3)
Elimino l'1 (la query deve ritornarmi 1)
ecc ecc.

Grazie 1000 a chi saprà darmi un aiuto.

Daniele G

5 Risposte

  • Re: Query per trovare primo numero libero

    NON SI PUO' FARE!

    NON in modo semplice, almeno.

    E il modo complicato E' abbastanza complicato!

    RICORDA che, fondamentalmente, hai a che fare con OPERAZIONI TRA INSIEMI.
    Quindi, DEVI CONVERTIRE la ricerca di un elemento NON PRESENTE in un insieme usando SOLO funzioni TRA INSIEMI!
  • Re: Query per trovare primo numero libero

    Che non si possa fare ( tra l'altro "urlato"....) ne dubito.
    Io sono arrivato fino a qui e inizia a funzionare, ma credo sia (come il tuo nick), migliorabile:

    sQuery = "SELECT TOP 1 ID_Code + 1 AS libero " & _
    "FROM Tab_Ingressi " & _
    "WHERE ((ID_Code + 1) NOT IN " & _
    "(SELECT ID_Code FROM Tab_Ingressi AS Tab_Ingressi_1))"
    Saluti
  • Re: Query per trovare primo numero libero

    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
  • Re: Query per trovare primo numero libero

    E' l'uovo di colombo!
    1) crei una tabella id_recupero
    2) quando cancelli un record inserisci l'id nella tabella id_recupero
    3) prima di inserire un record controlli che la tabella id_recupero contenga record (min Id)
    e il gioco e' fatto...
    ovviamente quando cancelli un record devi cancellare i record delle tabelle collegate
    opzione 2
    non cancelli il record ma solo i campi successivi all'id. poi esequi una query per min id con i campi settati a null
  • Re: Query per trovare primo numero libero

    Manca il secondo post di @migliorabile... effetto ghost pst sanremo???
    saluti omnia
    --
    Andrea
Devi accedere o registrarti per scrivere nel forum
5 risposte