Vermijd nummerconflicten met Microsoft SQL-reeksen
Opmerking:ik zal over dit onderwerp presenteren in de Access with SQL Server-groep online. Doe mee op 13 september om 18.30 uur CST, word lid van de groep om een e-mail te krijgen met alle details van de vergadering, het is gratis!
- Moet je garanderen dat een getal in een veld slechts één keer wordt gebruikt en nooit wordt gedupliceerd door een andere gebruiker?
- Heeft u een situatie gehad waarin u meer dan één automatische nummering in een tabel nodig had?
- Heeft u ooit een onder- en een bovengrens van opeenvolgende getallen nodig gehad en kon u er niet verder dan gaan?
- Heeft u soms een lijst met nummers die u wilt hergebruiken nadat u de laatste bent gepasseerd?
In SQL Server is er een functie die dit vrij gemakkelijk aankan, en dit wordt een reeks genoemd. Het is beschikbaar vanaf SQL Server 2012.
Net als een autonummer, kan het ervoor zorgen dat er elke keer een uniek nummer wordt uitgegeven, tenzij het wordt gerecycled.
Onlangs werd ik gevraagd om een reeks voor een klant te implementeren, waarbij meerdere gebruikers nieuwe records zullen maken en het volgende nummer in een specifieke reeks moeten "halen". We konden geen autonummering gebruiken omdat de klant beperkt was tot een bepaald bereik, niet om een bovengrens te overschrijden. Als de cijfers waren uitgeput, zou het management de reeks opnieuw aanvullen.
Waarom het gebruik van een Access-tabel niet werkt
Voorafgaand aan het upgraden naar SQL Server, zouden gebruikers een tabel delen die bijhoudt wat het volgende nummer is dat moet worden gebruikt. Het probleem met deze aanpak is dat het niet onfeilbaar is, twee gebruikers kunnen hetzelfde nummer op exact hetzelfde moment aanvragen, het overtreden van de bedrijfsregel.
Een SQL Server-reeks maken en gebruiken
Voordat u een reeks kunt gebruiken, moet deze worden gemaakt met de volgende syntaxis in SQL Server, u hoeft dit slechts één keer te doen:
CREATE SEQUENCE dbo.seqPolicyNumber AS int MIN 50005000 MAX 50005999;
Gebruik de volgende instructie om het volgende volgnummer op te halen:
SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue
Uw gebruikers hebben updaterechten nodig om de reeks te gebruiken, maar ze mogen het bereik van de reeks niet wijzigen. Updaterechten kunnen worden gegeven met behulp van deze syntaxis:
GRANT UPDATE ON dbo.seqPolicyNumber TO [MyDatabaseUserOrRole];
Om de volgende waarde van een reeks uit een Microsoft Access VBA-programma te halen, kunt u de volgende instructie gebruiken om de volgende waarde in een ADODB-recordset te lezen.
strSQL = "SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue"
OpenMyRecordset rs, strSQL
NextValue = rs("NextValue")
Dit is hoe we doorgaans een ADODB-recordset openen in ons bedrijf. Voor meer informatie over hoe u OpenMyRecordset kunt gebruiken, kunt u op een ander artikel in onze blog klikken:
Eenvoudige ADODB-recordsets en -opdrachten in Access
Het leuke van de syntaxis om het volgende volgnummer te krijgen, is dat het heel gemakkelijk te gebruiken is in T-SQL. U vervangt gewoon VOLGENDE WAARDE VOOR
INSERT dbo.Orders (OrderID, Name, Qty)
VALUES (NEXT VALUE FOR dbo.OrderNumberSequence, 'Tire', 2);
Meer flexibiliteit dan Autonummering
Een reeks kan meer flexibiliteit bieden dan een automatische nummering in Access of een IDENTITY-veld in SQL Server. Ten eerste kunt u slechts één autonummer- of identiteitsveld in een tabel hebben. Hoewel u een IDENTITY-veld opnieuw kunt gebruiken, kunt u geen waarden recyclen. IDENTITEIT-velden zijn nog steeds nuttig voor primaire sleutels, wanneer we een willekeurig nummer willen om het record te identificeren, en het heeft geen betekenis. Reeksbereiken kunnen echter een ingebedde betekenis hebben.
U bent ook niet beperkt tot het gebruik van gehele getallen zoals een IDENTITEIT, maar volgnummers kunnen ook decimaal of numeriek zijn. Je kunt ook naar beneden in je reeks ophogen in plaats van alleen maar omhoog.
Een reeks is ook niet gebonden aan een specifieke tabel en kan voor meerdere tabellen worden gebruikt, aangezien er voor een bepaalde tabel nieuwe volgnummers nodig zijn.
Vul de reeks aan
Als u het bereik voor een reeks wilt wijzigen, zoals wanneer u een nieuw bereik van polisnummers nodig hebt, moet u dit doen met een opgeslagen procedure. Het volgende is een opgeslagen procedure die dit kan doen.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
PROCEDURE MAKEN [dbo].[usp_AlterPolicySequence] (
@SeqName AS sysname,
@InpMin AS int,
@InpMax AS int
) MET UITVOEREN ALS EIGENAAR AS
BEGIN
STEL NOCOUNT IN;
VERKLAREN @sql nvarchar(MAX),
@err nvarchar(MAX);
INDIEN NIET BESTAAT (
SELECT NULL
FROM sys.sequences AS s
WHERE s.name =@SeqName
AND s.schema_id =SCHEMA_ID('dbo')
)
THROW 50000, 'De naam van de reeks is niet geldig.', 1;
ALS @InpMin NULL IS OF @InpMax NULL IS
THROW 50000, 'De waarden kunnen niet null zijn.', 1;
SET @sql =CONCAT(N'ALTER SEQUENCE [dbo].', QUOTENAME(@SeqName), N' RESTART WITH ', @InpMin, N' VERHOGING MET 1′, N' MINVALUE ', @InpMin, N' MAXVALUE ' , @InpMax, N' GEEN CYCLUS GEEN CACHE;');
EXEC sys.sp_executesql @sql;
;
EINDE
Er zijn enkele dingen die het vermelden waard zijn in deze opgeslagen procedure. Eerst draaien we het
MET UITVOEREN ALS EIGENAAR ALS.
We willen niet dat de dagelijkse gebruiker een volgorde kan veranderen. Maar we willen ze een beperkte mogelijkheid geven om het alleen via een opgeslagen procedure te wijzigen. (Gebruikers hebben alleen rechten nodig voor de opgeslagen procedure.)
GRANT EXECUTE ON dbo.usp_AlterPolicySequence TO [MyDatabaseUserOrRole];
Deze opgeslagen procedure kan worden uitgevoerd vanaf een Access-frontend, telkens wanneer een nieuw bereik in de reeks moet worden geïnstalleerd, en dat zou normaal gesproken door een admin-gebruiker zijn, die mogelijk meer SQL Server-rechten heeft dan een normale gebruiker.
Deze opgeslagen procedure kan echter ook worden uitgevoerd wanneer een nieuwe reeks getallen wacht om in de reeks te worden geladen, direct nadat de huidige reeks is opgebruikt. In dit geval kan de opgeslagen procedure worden aangeroepen door elke gebruiker die het eerste polisnummer voor het nieuwe bereik nodig heeft. Dus gebruiken we WITH EXECUTE AS OWNER AS om ze meer rechten te geven, alleen voor dit beperkte gebruik.
Een ander ding om op te merken is dat het nodig is om een SQL-string te construeren, en dan
EXEC sys.sp_executesql
te gebruiken
op die string, als we parameters gebruiken.
De volgende instructie werkt als deze in een SSMS-queryvenster wordt getypt of in een opgeslagen procedure wordt gebruikt.
ALTER SEQUENCE dbo.seqPolicyNumber
RESTART WITH 50005000
INCREMENT BY 1
MINVALUE 50005000
MAXVALUE 50005999
NO CYCLE
NO CACHE
Het volgende werkt echter niet met parameters in een opgeslagen procedure.
ALTER SEQUENCE dbo.seqPolicyNumber
RESTART WITH @InpMin
INCREMENT BY 1
MINVALUE @InpMin
MAXVALUE @InpMax
NO CYCLE
NO CACHE
Dus je moet de string-instructie samenstellen met de parameterwaarden erin geplakt.
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;
Deze string @sql is opgebouwd met de functies CONCAT en QUOTENAME. Het werkt ook als je plustekens hebt gebruikt om je laatste string te maken, maar het is beter om het te doen zoals in het voorbeeld dat Null-safe is.
Deze opgeslagen procedure zal een fout produceren (gooien) als u ontbrekende of slechte waarden opgeeft, en u mag niet doorgaan. Het genereert automatisch een fout als alle volgnummers zijn opgebruikt.
Uw front-end Access-procedure zou moeten controleren of er geen fout is opgetreden, wat alleen zou moeten optreden als de reeks geen nummers meer heeft, als u de juiste parameterinvoer geeft. Als er een fout wordt gezien, moet de front-end zijn bewerking op de een of andere manier annuleren.
Er zijn enkele andere mogelijkheden die u met argumenten kunt instellen. Met CYCLUS kan de reeks opnieuw worden doorlopen nadat deze het einde heeft bereikt en gaat vervolgens naar de MINVALUE. Je kunt het zelfs expliciet herstarten in het midden van een reeks door het een RESTART-waarde te geven.
Je kunt het ook een CACHE geven, je kunt bijvoorbeeld 50 volgnummers tegelijk vragen, en het werkt de systeemvolgordetabellen eens in de 50 nummers bij, wat sneller kan zijn, maar het voegt ook een risico toe als er een stroomstoring is , aangezien deze nummers niet opnieuw kunnen worden gebruikt
Het laatste dat het vermelden waard is in deze opgeslagen procedure, is dat u informatie (metagegevens) over uw sequenties kunt ophalen uit een systeemweergave genaamd sys.sequences. Het bevat de volgende informatie.
Enkele nuttige kolommen die u wellicht wilt lezen en aan een gebruiker wilt overbrengen, zijn minimumwaarde, maximumwaarde en huidige_waarde.
Als u geïnteresseerd bent, bevatten de volgende pagina's op MSDN zeer nuttige informatie over sequenties.
Volgnummers
Beschrijft reeksen en heeft zeer goede voorbeelden voor normaal gebruik
SEQUENTIE MAKEN (Transact-SQL)
WIJZIG VOLGORDE (Transact-SQL)
VOLGENDE WAARDE VOOR (Transact-SQL)
sys.sequences (Transact-SQL)
Beschrijft de metagegevens waarnaar u op uw reeksen kunt zoeken