Undgå talkonflikter med Microsoft SQL-sekvenser
Bemærk:Jeg vil præsentere om dette emne i Access with SQL Server-gruppen online. Slut dig til mig den 13. september kl. 18:30 CST. Tilmeld dig gruppen for at få en e-mail med alle mødedetaljerne, det er gratis!
- Behøver du at garantere, at et nummer i et felt kun bliver brugt én gang og aldrig bliver duplikeret af en anden bruger?
- Har du haft en situation, hvor du havde brug for mere end ét autonummer i en tabel?
- Har du nogensinde haft brug for en nedre og en øvre grænse for sekventielle tal, og du kunne ikke gå ud over den?
- Har du nogle gange en liste over numre, som du vil genbruge, efter du er kommet forbi det sidste?
I SQL Server er der en funktion, der ret nemt kan håndtere dette, og den kaldes en sekvens. Den er tilgængelig fra og med SQL Server 2012.
Ligesom et autonummer kan det sikre, at et unikt nummer bliver givet ud hver gang, medmindre det genbruges.
For nylig blev jeg bedt om at implementere en sekvens for en klient, hvor flere brugere vil oprette nye poster og skal "hente" det næste nummer i en bestemt sekvens. Vi kunne ikke bruge et autonummer, fordi kunden var begrænset til et bestemt område, for ikke at overskride en øvre tærskel. Når tallene var opbrugt, ville ledelsen genopbygge sekvensen igen.
Hvorfor det ikke virker at bruge en Access-tabel
Før opgradering til SQL Server, ville brugere dele en tabel, der ville holde styr på, hvad der er det næste tal, der skal bruges, problemet med denne tilgang er, at det ikke er idiotsikkert, to brugere kan anmode om det samme nummer på nøjagtig samme tid, overtrædelse af forretningsreglen.
Oprettelse og brug af en SQL Server-sekvens
Før du kan bruge en sekvens, skal den oprettes med følgende syntaks i SQL Server, du behøver kun at gøre dette én gang:
CREATE SEQUENCE dbo.seqPolicyNumber AS int MIN 50005000 MAX 50005999;
Brug følgende sætning til at hente det næste sekvensnummer:
VÆLG NÆSTE VÆRDI FOR dbo.seqPolicyNumber som NextValue
Dine brugere skal have opdateringstilladelser for at bruge sekvensen, men de bør ikke være i stand til at ændre rækkevidden af sekvensen. Opdateringstilladelser kan gives ved hjælp af denne syntaks:
GIV OPDATERING PÅ dbo.seqPolicyNumber TIL [MyDatabaseUserOrRole];
For at få den næste værdi af en sekvens fra et Microsoft Access VBA-program kan du bruge følgende sætning til at læse den næste værdi ind i et ADODB-postsæt.
strSQL ="SELECT NEXT VALUE FOR dbo .seqPolicyNumber as NextValue"
OpenMyRecordset rs, strSQL
NextValue =rs("NextValue")
Sådan åbner vi typisk et ADODB recordset i vores firma. For mere information om, hvordan du kan bruge OpenMyRecordset, kan du klikke på en anden artikel i vores blog:
Nem ADODB-postsæt og kommandoer i Access
Det fine ved syntaksen for at få det næste sekvensnummer er, at det er meget nemt at bruge i T-SQL. Du erstatter bare NEXT VALUE FOR
INSERT dbo.Orders (OrderID, Name, Quty)
VALUES (NEXT VALUE FOR dbo.OrderNumberSequence, 'Tire', 2);
Større fleksibilitet end Autonummerering
En sekvens kan tilbyde mere fleksibilitet end et autonummer i Access eller et IDENTITY-felt i SQL Server. For det første kan du kun have ét autonummer- eller identitetsfelt i en tabel. Selvom du kan gense et IDENTITY-felt, kan du ikke genbruge værdier. IDENTITY-felter er stadig nyttige for primærnøgler, når vi ønsker et vilkårligt nummer til at identificere posten, og det har ingen betydning. Sekvensområder kan dog have indlejret betydning.
Du er heller ikke begrænset til at bruge heltal som en IDENTITET, men sekvensnumre kan også være decimale eller numeriske. Du kan også stige ned i din sekvens i stedet for bare op.
En sekvens er heller ikke bundet til nogen specifik tabel og kan bruges på tværs af tabeller, da nye sekvensnumre er nødvendige for en bestemt tabel.
Genopfyld sekvensen
Når du vil ændre rækkevidden for en sekvens, som når du har brug for et nyt område af policenumre, skal det gøres med en lagret procedure. Følgende er en lagret procedure, der kan gøre dette.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
OPRET PROCEDURE [dbo].[usp_AlterPolicySequence] (
@SeqName AS sysname,
@InpMin AS int,
@InpMax AS int
) MED UDFØR SOM EJER SOM
BEGYND
INDSTILL INGEN TÆLLING TIL;
DEKLARE @sql nvarchar(MAX),
@err nvarchar(MAX);
HVIS IKKE FINDER (
VÆLG NULL
FRA sys.sequences AS s
HVOR s.name =@SeqName
OG s.schema_id =SCHEMA_ID('dbo')
)
THROW 50000, 'Sekvensnavnet er ikke gyldigt.', 1;
HVIS @InpMin ER NULL ELLER @InpMax ER NULL
KAST 50000, 'Værdierne kan ikke være nul.', 1;
SET @sql =CONCAT(N'ALTER SEQUENCE [dbo].', QUOTENAME(@SeqName), N' GENSTART MED ', @InpMin, N' FORØG MED 1′, N' MINVALUE ', @InpMin, N' MAXVALUE ' , @InpMax, N' NO CYCLE NO CACHE;');
EXEC sys.sp_executesql @sql;
;
SLUT
Der er nogle ting, der er værd at bemærke i denne lagrede procedure. Først kører vi det
MED EXECUTE AS OWNER AS.
Vi ønsker ikke, at den daglige bruger skal kunne ændre en rækkefølge. Men vi ønsker kun at give dem begrænset mulighed for at ændre det gennem en lagret procedure. (Brugere behøver kun rettigheder til den lagrede procedure.)
GIV UDFØR PÅ dbo.usp_AlterPolicySequence TIL [MyDatabaseUserOrRole];
Denne lagrede procedure kan køres fra en Access-frontend, når et nyt område i sekvensen skal installeres, og det ville normalt være af en admin-bruger, som måske har flere SQL Server-privilegier end en normal bruger.
Denne lagrede procedure kan dog også køres, når en ny række numre venter på at blive indlæst i sekvensen, lige efter at den aktuelle sekvens er brugt op. I dette tilfælde kan den lagrede procedure kaldes af enhver bruger, der har brug for det første politiknummer for det nye område. Så vi bruger WITH EXECUTE AS OWNER AS for at give dem flere rettigheder kun til denne begrænsede brug.
En anden ting at bemærke er, at det er nødvendigt at konstruere en SQL-streng og derefter bruge
EXEC sys.sp_executesql
på den streng, hvis vi bruger parametre.
Følgende sætning fungerer, hvis den indtastes i et SSMS-forespørgselsvindue eller bruges i en lagret procedure.
ALTER SEQUENCE dbo.seqPolicyNumber
GENSTART MED 50005000
FORØG MED 1
MINVÆRDI 50005000
MAKSVÆRDI 50005999
INGEN CYKLUS INGEN CACHE
Følgende vil dog ikke fungere ved brug af parametre i en lagret procedure.
ÆNDRINGSSEKVENS dbo.seqPolicyNumber
GENSTART MED @InpMin
FORØG MED 1
MINVALUE @ InpMin
MAXVALUE @InpMax
INGEN CYKLUS
INGEN CACHE
Så du skal konstruere strengsætningen med parameterværdierne indsat.
SET @sql =CONCAT(N'ALTER SEQUENCE [dbo].', QUOTENAME(@SeqName), N' GENSTART MED ', @InpMin, N' FORØG MED 1', N' MINVALUE ', @InpMin, N' MAXVALUE ', @InpMax, N' NO CYCLE NO CACHE;');
EXEC sys.sp_executesql @sql;
Denne streng @sql er konstrueret ved hjælp af funktionerne CONCAT og QUOTENAME. Det vil også fungere, hvis du brugte plustegn til at lave din endelige streng, men det er bedre at gøre det som eksemplet, der er null sikkert.
Denne lagrede procedure vil producere (kaste) en fejl, hvis du angiver manglende eller dårlige værdier, og du får ikke lov til at fortsætte. Det vil automatisk generere en fejl, hvis alle sekvensnumrene er brugt op.
Din frontend Access-procedure bør kontrollere, at der ikke er opstået en fejl, som kun bør opstå, hvis sekvensen løber tør for tal, hvis du angiver korrekte parameterinput. Hvis der ses en fejl, skal frontenden på en eller anden måde annullere sin handling.
Der er nogle andre muligheder, du kan indstille med argumenter. CYCLE vil tillade sekvensen at cykle igen, efter at den når slutningen, og derefter gå til MINVÆRDI. Du kan endda eksplicit genstarte den midt i en sekvens ved at give den en RESTART-værdi.
Du kan også give den en CACHE, for eksempel kan du bede om 50 sekvensnumre ad gangen, og den opdaterer systemsekvenstabellerne én gang for 50 tal, hvilket kan være hurtigere, men det tilføjer også en risiko, hvis der er strømsvigt , da disse numre ikke kan genbruges
Den sidste ting, der er værd at bemærke i denne lagrede procedure, er, at du kan trække information (meta-data) om dine sekvenser fra en systemvisning kaldet sys.sequences. Den indeholder følgende oplysninger.
Nogle nyttige kolonner, du måske gerne vil læse og formidle til en bruger, er minimum_value, maximum_value og nuværende_værdi.
Hvis du er interesseret, har de følgende sider på MSDN meget nyttige oplysninger om sekvenser.
Sekvensnumre
Beskriver sekvenser og har meget gode eksempler til typisk brug
OPRET SEKVENS (Transact-SQL)
ALTER SEQUENCE (Transact-SQL)
NÆSTE VÆRDI FOR (Transact-SQL)
sys.sequences (Transact-SQL)
Beskriver de metadata, du kan forespørge efter på dine sekvenser