Evita conflitti di numeri con le sequenze Microsoft SQL
Nota:presenterò questo argomento nel gruppo Accesso con SQL Server online. Unisciti a me il 13 settembre alle 18:30 CST, unisciti al gruppo per ricevere un'e-mail con tutti i dettagli della riunione, è gratis!
- Devi garantire che un numero in un campo venga utilizzato una sola volta e mai duplicato da un altro utente?
- Hai avuto una situazione in cui avevi bisogno di più di una numerazione automatica in una tabella?
- Hai mai avuto bisogno di un limite inferiore e superiore di numeri sequenziali e non potevi oltrepassarlo?
- A volte hai un elenco di numeri che vuoi riciclare dopo aver superato l'ultimo?
In SQL Server è presente una funzionalità in grado di gestirlo abbastanza facilmente e si chiama sequenza. È disponibile a partire da SQL Server 2012.
Come un numero automatico, può garantire che ogni volta venga assegnato un numero univoco, a meno che non venga riciclato.
Di recente mi è stato chiesto di implementare una sequenza per un client, in cui più utenti creeranno nuovi record e dovranno "prendere" il numero successivo in una sequenza specifica. Non abbiamo potuto utilizzare un numero automatico perché il cliente era limitato a un determinato intervallo, per non superare una soglia superiore. Quando i numeri si fossero esauriti, la direzione avrebbe rifornito di nuovo la sequenza.
Perché l'utilizzo di una tabella di Access non funziona
Prima di eseguire l'aggiornamento a SQL Server, gli utenti condividevano una tabella che teneva d'occhio qual è il numero successivo da utilizzare, il problema con questo approccio è che non è infallibile, due utenti possono richiedere lo stesso numero esattamente allo stesso tempo, violare la regola aziendale.
Creazione e utilizzo di una sequenza SQL Server
Prima di poter utilizzare una sequenza, è necessario crearla con la sintassi seguente in SQL Server, è necessario eseguire questa operazione solo una volta:
CREATE SEQUENCE dbo.seqPolicyNumber AS int MIN 50005000 MAX 50005999;
Utilizzare la seguente istruzione per recuperare il numero di sequenza successivo:
SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue
I tuoi utenti avranno bisogno delle autorizzazioni di aggiornamento per utilizzare la sequenza, ma non dovrebbero essere in grado di modificare l'intervallo della sequenza. Le autorizzazioni di aggiornamento possono essere concesse utilizzando questa sintassi:
GRANT UPDATE ON dbo.seqPolicyNumber TO [MyDatabaseUserOrRole];
Per ottenere il valore successivo di una sequenza da un programma VBA di Microsoft Access, è possibile utilizzare la seguente istruzione per leggere il valore successivo in un recordset ADODB.
strSQL = "SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue"
OpenMyRecordset rs, strSQL
NextValue = rs("NextValue")
Questo è il modo in cui in genere apriamo un recordset ADODB nella nostra azienda. Per ulteriori informazioni su come utilizzare OpenMyRecordset, puoi fare clic su un altro articolo nel nostro blog:
Recordset e comandi ADODB facili in Access
La cosa bella della sintassi per ottenere il numero di sequenza successivo è che è molto facile da usare in T-SQL. Sostituisci semplicemente NEXT VALUE FOR
INSERT dbo.Orders (OrderID, Name, Qty)
VALUES (NEXT VALUE FOR dbo.OrderNumberSequence, 'Tire', 2);
Più flessibilità rispetto a Autonumber
Una sequenza può offrire maggiore flessibilità rispetto a una numerazione automatica in Access oa un campo IDENTITÀ in SQL Server. Innanzitutto, puoi avere un solo campo di numerazione automatica o identità in una tabella. Sebbene tu possa riseminare un campo IDENTITY, non puoi riciclare i valori. I campi IDENTITY sono ancora utili per le chiavi primarie, quando vogliamo che un numero arbitrario identifichi il record e non ha significato. Tuttavia, gli intervalli di sequenze possono avere un significato incorporato.
Inoltre, non sei limitato all'utilizzo di numeri interi come IDENTITY, ma i numeri di sequenza possono anche essere decimali o numerici. Inoltre puoi aumentare la sequenza verso il basso invece che verso l'alto.
Inoltre, una sequenza non è legata a nessuna tabella specifica e può essere utilizzata su più tabelle poiché sono necessari nuovi numeri di sequenza per una tabella particolare.
Rifornisci la sequenza
Quando si desidera modificare l'intervallo per una sequenza, ad esempio quando è necessario un nuovo intervallo di numeri di criteri, è necessario farlo con una stored procedure. Quella che segue è una procedura memorizzata che può eseguire questa operazione.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[usp_AlterPolicySequence] (
@SeqName AS sysname,
@InpMin AS int,
@InpMax AS int
) CON EXECUTE AS OWNER AS
BEGIN
IMPOSTA NESSUN NUMERO SU;
DICHIARA @sql nvarchar(MAX),
@err nvarchar(MAX);
SE NON ESISTE (
SELECT NULL
FROM sys.sequences AS s
DOVE s.name =@SeqName
AND s.schema_id =SCHEMA_ID('dbo')
)
THROW 50000, 'Il nome della sequenza non è valido.', 1;
SE @InpMin IS NULL O @InpMax IS NULL
LANCIA 50000, 'I valori non possono essere null.', 1;
SET @sql =CONCAT(N'ALTER SEQUENCE [dbo].', QUOTENAME(@SeqName), N' RESTART WITH ', @InpMin, N' INCREMENT BY 1', N' MINVALUE ', @InpMin, N' MAXVALUE ' , @InpMax, N' NESSUN CICLO NESSUNA CACHE;');
ESEGUI sys.sp_executesql @sql;
;
FINE
Ci sono alcune cose degne di nota in questa procedura memorizzata. Per prima cosa lo eseguiamo
CON EXECUTE AS OWNER AS.
Non vogliamo che l'utente di tutti i giorni sia in grado di modificare una sequenza. Ma vogliamo dare loro una capacità limitata di modificarlo solo attraverso una procedura memorizzata. (Gli utenti necessitano solo dei diritti sulla procedura memorizzata.)
GRANT EXECUTE ON dbo.usp_AlterPolicySequence TO [MyDatabaseUserOrRole];
Questa procedura memorizzata può essere eseguita da un front-end di Access, ogni volta che è necessario installare un nuovo intervallo nella sequenza e ciò normalmente avverrebbe da un utente amministratore, che potrebbe disporre di più privilegi di SQL Server rispetto a un utente normale.
Tuttavia, questa procedura memorizzata può essere eseguita anche quando un nuovo intervallo di numeri è in attesa di essere caricato nella sequenza, subito dopo che la sequenza corrente è esaurita. In questo caso la procedura memorizzata potrebbe essere chiamata da qualsiasi utente che necessiti del primo numero di policy per il nuovo intervallo. Quindi utilizziamo WITH EXECUTE AS OWNER AS per dare loro più diritti solo per questo uso limitato.
Un'altra cosa da notare è che è necessario costruire una stringa SQL, quindi utilizzare
EXEC sys.sp_executesql
su quella stringa, se stiamo usando parametri.
La seguente istruzione funzionerà se digitata in una finestra di query SSMS o utilizzata in una procedura memorizzata.
ALTER SEQUENCE dbo.seqPolicyNumber
RESTART WITH 50005000
INCREMENT BY 1
MINVALUE 50005000
MAXVALUE 50005999
NO CYCLE
NO CACHE
Tuttavia, quanto segue non funzionerà utilizzando i parametri in una stored procedure.
ALTER SEQUENCE dbo.seqPolicyNumber
RESTART WITH @InpMin
INCREMENT BY 1
MINVALUE @InpMin
MAXVALUE @InpMax
NO CYCLE
NO CACHE
Quindi è necessario costruire l'istruzione stringa con i valori dei parametri incollati.
SET @sql = CONCAT(N'ALTER SEQUENCE [dbo].', QUOTENAME(@SeqName), N' RESTART WITH ', @InpMin, N' INCREMENT BY 1', N' MINVALUE ', @InpMin, N' MAXVALUE ', @InpMax, N' NO CYCLE NO CACHE;');
EXEC sys.sp_executesql @sql;
Questa stringa @sql è costruita utilizzando le funzioni CONCAT e QUOTENAME. Funzionerà anche se hai usato i segni più per creare la tua stringa finale, ma è meglio farlo come nell'esempio che è Null sicuro.
Questa procedura memorizzata produrrà (emetterà) un errore se fornisci valori mancanti o non validi e non ti sarà consentito continuare. Genera automaticamente un errore se tutti i numeri di sequenza sono esauriti.
La tua procedura di accesso front-end dovrebbe verificare che non si sia verificato un errore, che dovrebbe verificarsi solo se la sequenza esaurisce i numeri, se stai fornendo input di parametri appropriati. Se viene visualizzato un errore, il front-end dovrà annullare in qualche modo il suo funzionamento.
Ci sono alcune altre capacità che puoi impostare con gli argomenti. CYCLE consentirà alla sequenza di ripetere il ciclo dopo aver raggiunto la fine, quindi andrà al MINVALUE. Puoi persino riavviarlo in modo esplicito nel mezzo di una sequenza assegnandogli un valore RESTART.
Puoi anche assegnargli una CACHE, ad esempio puoi chiedere 50 numeri di sequenza alla volta e aggiorna le tabelle di sequenza del sistema una volta ogni 50 numeri, il che può essere più veloce, ma aggiunge anche un rischio in caso di interruzione di corrente , poiché questi numeri non possono essere riutilizzati
L'ultima cosa degna di nota in questa procedura memorizzata è che puoi estrarre informazioni (meta-dati) sulle tue sequenze da una vista di sistema chiamata sys.sequences. Contiene le seguenti informazioni.
Alcune colonne utili che potresti voler leggere e trasmettere a un utente sono valore_minimo, valore_massimo e valore_corrente.
Se sei interessato, le seguenti pagine su MSDN contengono informazioni molto utili sulle sequenze.
Numeri di sequenza
Descrive le sequenze e offre ottimi esempi per l'uso tipico
CREA SEQUENZA (Transact-SQL)
ALTER SEQUENCE (Transact-SQL)
NEXT VALUE FOR (Transact-SQL)
sys.sequences (Transact-SQL)
Descrive i metadati su cui è possibile eseguire query nelle sequenze