Access
 sql >> Datenbank >  >> RDS >> Access

Vermeiden Sie Nummernkonflikte mit Microsoft SQL-Sequenzen

Vermeiden Sie Nummernkonflikte mit Microsoft SQL-Sequenzen

Hinweis:Ich werde zu diesem Thema in der Access with SQL Server-Gruppe online einen Vortrag halten. Bitte besuchen Sie mich am 13. September um 18:30 Uhr CST, treten Sie der Gruppe bei, um eine E-Mail mit allen Besprechungsdetails zu erhalten. Es ist kostenlos!

  • Müssen Sie garantieren, dass eine Zahl in einem Feld nur einmal verwendet und niemals von einem anderen Benutzer dupliziert wird?
  • Hatten Sie eine Situation, in der Sie mehr als eine Autonummer in einer Tabelle benötigten?
  • Haben Sie jemals eine untere und eine obere Grenze für fortlaufende Nummern benötigt, und Sie konnten nicht darüber hinausgehen?
  • Haben Sie manchmal eine Liste mit Nummern, die Sie recyceln möchten, nachdem Sie die letzte überwunden haben?

In SQL Server gibt es eine Funktion, die dies recht einfach handhaben kann und die als Sequenz bezeichnet wird. Es ist ab SQL Server 2012 verfügbar.

Wie eine Autonummer kann sie sicherstellen, dass jedes Mal eine eindeutige Nummer ausgegeben wird, es sei denn, sie wird wiederverwendet.

Kürzlich wurde ich gebeten, eine Sequenz für einen Kunden zu implementieren, bei der mehrere Benutzer neue Datensätze erstellen und die nächste Nummer in einer bestimmten Sequenz „holen“ müssen. Wir konnten keine automatische Nummer verwenden, da der Kunde auf einen bestimmten Bereich beschränkt war, um eine obere Schwelle nicht zu überschreiten. Wenn die Anzahl erschöpft war, füllte das Management die Sequenz erneut auf.

Warum die Verwendung einer Access-Tabelle nicht funktioniert

Vor dem Upgrade auf SQL Server würden Benutzer eine Tabelle teilen, die die nächste zu verwendende Nummer im Auge behalten würde. Das Problem bei diesem Ansatz ist, dass es nicht narrensicher ist, zwei Benutzer können genau zur gleichen Zeit dieselbe Nummer anfordern. Verstoß gegen die Geschäftsregel.

Erstellen und Verwenden einer SQL Server-Sequenz

Bevor Sie eine Sequenz verwenden können, muss sie mit der folgenden Syntax in SQL Server erstellt werden, Sie müssen dies nur einmal tun:
CREATE SEQUENCE dbo.seqPolicyNumber AS int MIN 50005000 MAX 50005999;
Verwenden Sie die folgende Anweisung, um die nächste Sequenznummer abzurufen:
SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue
Ihre Benutzer benötigen Aktualisierungsberechtigungen, um die Sequenz zu verwenden, aber sie sollten nicht in der Lage sein, den Bereich der Sequenz zu ändern. Aktualisierungsberechtigungen können mit dieser Syntax erteilt werden:
GRANT UPDATE ON dbo.seqPolicyNumber TO [MyDatabaseUserOrRole];
Um den nächsten Wert einer Sequenz aus einem Microsoft Access VBA-Programm zu erhalten, können Sie die folgende Anweisung verwenden, um den nächsten Wert in ein ADODB-Recordset einzulesen.
strSQL = "SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue"
OpenMyRecordset rs, strSQL
NextValue = rs("NextValue")

So öffnen wir normalerweise ein ADODB-Recordset in unserer Firma. Für weitere Informationen darüber, wie Sie OpenMyRecordset verwenden können, können Sie auf einen anderen Artikel in unserem Blog klicken:

Einfache ADODB-Datensätze und -Befehle in Access

Das Schöne an der Syntax zum Abrufen der nächsten Sequenznummer ist, dass sie in T-SQL sehr einfach zu verwenden ist. Sie ersetzen einfach NÄCHSTER WERT FÜR , wo Sie normalerweise einen Wert aus einem Feldnamen, Parameter oder einer Konstante erhalten würden. Das Folgende zeigt, wie es in einer Insert-Anweisung verwendet werden kann.
INSERT dbo.Orders (OrderID, Name, Qty)
VALUES (NEXT VALUE FOR dbo.OrderNumberSequence, 'Tire', 2);

Mehr Flexibilität als Autonumber

Eine Sequenz kann mehr Flexibilität bieten als eine automatische Nummer in Access oder ein IDENTITY-Feld in SQL Server. Erstens können Sie nur ein Autonumber- oder Identitätsfeld in einer Tabelle haben. Sie können ein IDENTITY-Feld zwar neu setzen, aber Sie können keine Werte wiederverwenden. IDENTITY-Felder sind immer noch nützlich für Primärschlüssel, wenn wir wollen, dass eine willkürliche Zahl den Datensatz identifiziert, und sie keine Bedeutung hat. Sequenzbereiche können jedoch eine eingebettete Bedeutung haben.

Sie sind auch nicht darauf beschränkt, ganze Zahlen wie eine IDENTITÄT zu verwenden, aber Sequenznummern können auch dezimal oder numerisch sein. Außerdem können Sie in Ihrer Sequenz nach unten statt nur nach oben zählen.

Außerdem ist eine Sequenz nicht an eine bestimmte Tabelle gebunden und kann tabellenübergreifend verwendet werden, da für eine bestimmte Tabelle neue Sequenznummern benötigt werden.

Ergänze die Sequenz

Wenn Sie den Bereich für eine Sequenz ändern möchten, z. B. wenn Sie einen neuen Bereich von Policennummern benötigen, sollte dies mit einer gespeicherten Prozedur erfolgen. Das Folgende ist eine gespeicherte Prozedur, die dies tun kann.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[usp_AlterPolicySequence] (
@SeqName AS Systemname,
@InpMin AS int,
@InpMax AS int
) MIT AUSFÜHREN ALS EIGENTÜMER AS
BEGIN
NOCOUNT EINSTELLEN;

DECLARE @sql nvarchar(MAX),
@err nvarchar(MAX);

WENN NICHT VORHANDEN (
SELECT NULL
FROM sys.sequences AS s
WHERE s.name =@SeqName
AND s.schema_id =SCHEMA_ID('dbo')
)
THROW 50000, 'Der Sequenzname ist ungültig.', 1;

IF @InpMin IS NULL OR @InpMax IS NULL
THROW 50000, ‘Die Werte dürfen nicht Null sein.’, 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' NO CYCLE NO CACHE;');
EXEC sys.sp_executesql @sql;

;

ENDE

Bei dieser gespeicherten Prozedur sind einige Dinge zu beachten. Zuerst führen wir es
WITH EXECUTE AS OWNER AS.

aus

Wir möchten nicht, dass der normale Benutzer eine Sequenz ändern kann. Wir möchten ihnen jedoch die begrenzte Möglichkeit geben, sie nur über eine gespeicherte Prozedur zu ändern. (Benutzer benötigen nur Rechte für die gespeicherte Prozedur.)
GRANT EXECUTE ON dbo.usp_AlterPolicySequence TO [MyDatabaseUserOrRole];
Diese gespeicherte Prozedur kann von einem Access-Front-End ausgeführt werden, wenn ein neuer Bereich in der Sequenz installiert werden muss, und das würde normalerweise von einem Admin-Benutzer erfolgen, der möglicherweise mehr SQL Server-Berechtigungen als ein normaler Benutzer hat.

Diese gespeicherte Prozedur könnte jedoch auch ausgeführt werden, wenn ein neuer Nummernbereich darauf wartet, in die Sequenz geladen zu werden, direkt nachdem die aktuelle Sequenz aufgebraucht ist. In diesem Fall könnte die gespeicherte Prozedur von jedem Benutzer aufgerufen werden, der die erste Policennummer für den neuen Bereich benötigt. Also verwenden wir WITH EXECUTE AS OWNER AS, um ihnen mehr Rechte nur für diese eingeschränkte Verwendung zu geben.

Eine weitere zu beachtende Sache ist, dass es notwendig ist, einen SQL-String zu erstellen und dann
EXEC sys.sp_executesql
zu verwenden

auf dieser Zeichenfolge, wenn wir Parameter verwenden.

Die folgende Anweisung funktioniert, wenn sie in ein SSMS-Abfragefenster eingegeben oder in einer gespeicherten Prozedur verwendet wird.

ALTER SEQUENCE dbo.seqPolicyNumber
RESTART WITH 50005000
INCREMENT BY 1
MINVALUE 50005000
MAXVALUE 50005999
NO CYCLE
NO CACHE

Folgendes funktioniert jedoch nicht mit Parametern in einer gespeicherten Prozedur.
ALTER SEQUENCE dbo.seqPolicyNumber
RESTART WITH @InpMin
INCREMENT BY 1
MINVALUE @InpMin
MAXVALUE @InpMax
NO CYCLE
NO CACHE

Sie müssen also die String-Anweisung mit den eingefügten Parameterwerten erstellen.
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;
Dieser String @sql wird mit den Funktionen CONCAT und QUOTENAME konstruiert. Es funktioniert auch, wenn Sie Pluszeichen verwendet haben, um Ihre endgültige Zeichenfolge zu erstellen, aber es ist besser, es wie im Beispiel zu machen, das Null-sicher ist.

Diese gespeicherte Prozedur erzeugt (wirft) einen Fehler, wenn Sie fehlende oder ungültige Werte angeben, und Sie können nicht fortfahren. Es wird automatisch ein Fehler generiert, wenn alle Sequenznummern aufgebraucht sind.

Ihre Front-End-Zugriffsprozedur sollte überprüfen, ob kein Fehler aufgetreten ist, der nur auftreten sollte, wenn die Sequenz keine Zahlen mehr enthält, wenn Sie die richtigen Parametereingaben bereitstellen. Wenn ein Fehler auftritt, muss das Frontend seinen Vorgang irgendwie abbrechen.

Es gibt einige andere Fähigkeiten, die Sie mit Argumenten festlegen können. CYCLE lässt die Sequenz erneut durchlaufen, nachdem sie das Ende erreicht hat, und geht dann zum MINVALUE. Sie können es sogar mitten in einer Sequenz explizit neu starten, indem Sie ihm einen RESTART-Wert geben.

Sie können ihm auch einen CACHE geben, zum Beispiel können Sie 50 Sequenznummern gleichzeitig anfordern, und es aktualisiert die Systemsequenztabellen einmal alle 50 Nummern, was schneller sein kann, aber es fügt auch ein Risiko hinzu, wenn es einen Stromausfall gibt , da diese Nummern nicht wiederverwendet werden können

Das Letzte, was in dieser gespeicherten Prozedur erwähnenswert ist, ist, dass Sie Informationen (Metadaten) über Ihre Sequenzen aus einer Systemansicht namens sys.sequences abrufen können. Es enthält die folgenden Informationen.


Einige nützliche Spalten, die Sie vielleicht lesen und einem Benutzer mitteilen möchten, sind minimum_value, maximum_value und aktueller_wert.


Falls Sie daran interessiert sind, finden Sie auf den folgenden Seiten auf MSDN sehr nützliche Informationen zu Sequenzen.

Sequenznummern
Beschreibt Sequenzen und enthält sehr gute Beispiele für die typische Verwendung

SEQUENZ ERSTELLEN (Transact-SQL)

ALTER SEQUENCE (Transact-SQL)

NÄCHSTER WERT FÜR (Transact-SQL)

sys.sequences (Transact-SQL)
Beschreibt die Metadaten, die Sie für Ihre Sequenzen abfragen können