Access
 sql >> Base de données >  >> RDS >> Access

Éviter les conflits de nombres avec les séquences Microsoft SQL

Éviter les conflits de nombres avec les séquences Microsoft SQL

Remarque :Je ferai une présentation sur ce sujet dans le groupe Access with SQL Server en ligne. Rejoignez-moi le 13 septembre à 18h30 CST, rejoignez le groupe pour recevoir un e-mail avec tous les détails de la réunion, c'est gratuit !

  • Avez-vous besoin de garantir qu'un numéro dans un champ ne sera utilisé qu'une seule fois et ne sera jamais dupliqué par un autre utilisateur ?
  • Avez-vous déjà eu besoin de plusieurs numéros automatiques dans une table ?
  • Avez-vous déjà eu besoin d'une limite inférieure et supérieure de nombres séquentiels, et vous ne pouviez pas aller au-delà ?
  • Avez-vous parfois une liste de numéros que vous souhaitez recycler après avoir dépassé le dernier ?

Dans SQL Server, il existe une fonctionnalité qui peut gérer cela assez facilement et qui s'appelle une séquence. Il est disponible à partir de SQL Server 2012.

Comme un numéro automatique, il peut garantir qu'un numéro unique sera attribué à chaque fois, à moins qu'il ne soit recyclé.

Récemment, on m'a demandé d'implémenter une séquence pour un client, où plusieurs utilisateurs créeront de nouveaux enregistrements et devront «récupérer» le numéro suivant dans une séquence spécifique. Nous ne pouvions pas utiliser un numéro automatique car le client était limité à une certaine plage, pour ne pas dépasser un seuil supérieur. Lorsque les numéros étaient épuisés, la direction reconstituait la séquence à nouveau.

Pourquoi l'utilisation d'une table Access ne fonctionne pas

Avant la mise à niveau vers SQL Server, les utilisateurs partageaient une table qui garderait un œil sur le prochain numéro à utiliser, le problème avec cette approche est qu'elle n'est pas infaillible, deux utilisateurs peuvent demander le même numéro exactement au même moment, violation de la règle métier.

Créer et utiliser une séquence SQL Server

Avant de pouvoir utiliser une séquence, elle doit être créée avec la syntaxe suivante dans SQL Server, vous n'avez besoin de le faire qu'une seule fois :
CREATE SEQUENCE dbo.seqPolicyNumber AS int MIN 50005000 MAX 50005999;
Utilisez l'instruction suivante pour récupérer le numéro de séquence suivant :
SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue
Vos utilisateurs auront besoin d'autorisations de mise à jour pour utiliser la séquence, mais ils ne doivent pas pouvoir modifier la plage de la séquence. Les autorisations de mise à jour peuvent être accordées à l'aide de cette syntaxe :
GRANT UPDATE ON dbo.seqPolicyNumber TO [MyDatabaseUserOrRole];
Pour obtenir la valeur suivante d'une séquence à partir d'un programme Microsoft Access VBA, vous pouvez utiliser l'instruction suivante pour lire la valeur suivante dans un jeu d'enregistrements ADODB.
strSQL = "SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue"
OpenMyRecordset rs, strSQL
NextValue = rs("NextValue")

C'est ainsi que nous ouvrons généralement un jeu d'enregistrements ADODB dans notre entreprise. Pour plus d'informations sur l'utilisation d'OpenMyRecordset, vous pouvez cliquer sur un autre article de notre blog :

Jeux d'enregistrements et commandes ADODB faciles dans Access

La bonne chose à propos de la syntaxe pour obtenir le numéro de séquence suivant est qu'elle est très facile à utiliser dans T-SQL. Vous remplacez simplement NEXT VALUE FOR là où vous obtiendriez normalement une valeur à partir d'un nom de champ, d'un paramètre ou d'une constante. Ce qui suit montre comment il peut être utilisé dans une instruction Insert.
INSERT dbo.Orders (OrderID, Name, Qty)
VALUES (NEXT VALUE FOR dbo.OrderNumberSequence, 'Tire', 2);

Plus de flexibilité que la numérotation automatique

Une séquence peut offrir plus de flexibilité qu'une numérotation automatique dans Access ou qu'un champ IDENTITY dans SQL Server. Tout d'abord, vous ne pouvez avoir qu'un seul champ de numérotation automatique ou d'identité dans une table. Bien que vous puissiez réamorcer un champ IDENTITY, vous ne pouvez pas recycler les valeurs. Les champs IDENTITY sont toujours utiles pour les clés primaires, lorsque nous voulons un nombre arbitraire pour identifier l'enregistrement, et cela n'a aucune signification. Les plages de séquences peuvent cependant avoir une signification intégrée.

Vous n'êtes pas non plus limité à l'utilisation d'entiers comme une IDENTITÉ, mais les numéros de séquence peuvent également être décimaux ou numériques. Vous pouvez également incrémenter vers le bas dans votre séquence au lieu de simplement vers le haut.

De plus, une séquence n'est liée à aucune table spécifique et peut être utilisée dans toutes les tables car de nouveaux numéros de séquence sont nécessaires pour une table particulière.

Réapprovisionner la séquence

Lorsque vous souhaitez modifier la plage d'une séquence, comme lorsque vous avez besoin d'une nouvelle plage de numéros de stratégie, cela doit être fait avec une procédure stockée. Voici une procédure stockée qui peut le faire.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[usp_AlterPolicySequence] (
@SeqName AS sysname,
@InpMin AS int,
@InpMax AS int
) AVEC EXECUTE AS OWNER AS
COMMENCER
DÉFINIR NOCOUNT ON ;

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

IF NOT EXISTS (
SELECT NULL
FROM sys.sequences AS s
WHERE s.name =@SeqName
AND s.schema_id =SCHEMA_ID('dbo')
)
THROW 50000, 'Le nom de la séquence n'est pas valide.', 1;

IF @InpMin IS NULL OU @InpMax IS NULL
THROW 50000, ‘Les valeurs ne peuvent pas être nulles.’, 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' PAS DE CYCLE PAS DE CACHE ;');
EXEC sys.sp_executesql @sql;

;

FIN

Il y a certaines choses à noter dans cette procédure stockée. Nous l'exécutons d'abord
AVEC EXECUTE AS OWNER AS.

Nous ne voulons pas que l'utilisateur ordinaire puisse modifier une séquence. Mais nous voulons leur donner une capacité limitée de le modifier uniquement via une procédure stockée. (Les utilisateurs n'ont besoin que des droits sur la procédure stockée.)
GRANT EXECUTE ON dbo.usp_AlterPolicySequence TO [MyDatabaseUserOrRole];
Cette procédure stockée peut être exécutée à partir d'un frontal d'accès, chaque fois qu'une nouvelle plage dans la séquence doit être installée, et ce serait normalement par un utilisateur administrateur, qui pourrait avoir plus de privilèges SQL Server qu'un utilisateur normal.

Cependant, cette procédure stockée peut également être exécutée lorsqu'une nouvelle plage de nombres attend d'être chargée dans la séquence, juste après que la séquence actuelle est épuisée. Dans ce cas, la procédure stockée peut être appelée par n'importe quel utilisateur qui a besoin du premier numéro de stratégie pour la nouvelle plage. Nous utilisons donc WITH EXECUTE AS OWNER AS pour leur donner plus de droits uniquement pour cette utilisation limitée.

Une autre chose à noter est qu'il est nécessaire de construire une chaîne SQL, puis d'utiliser
EXEC sys.sp_executesql

sur cette chaîne, si nous utilisons des paramètres.

L'instruction suivante fonctionnera si elle est saisie dans une fenêtre de requête SSMS ou utilisée dans une procédure stockée.

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

Cependant, ce qui suit ne fonctionnera pas en utilisant des paramètres dans une procédure stockée.
ALTER SEQUENCE dbo.seqPolicyNumber
RESTART WITH @InpMin
INCREMENT BY 1
MINVALUE @InpMin
MAXVALUE @InpMax
NO CYCLE
NO CACHE

Vous devez donc construire l'instruction de chaîne avec les valeurs de paramètre collées.
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;
Cette chaîne @sql est construite à l'aide des fonctions CONCAT et QUOTENAME. Cela fonctionnera également si vous avez utilisé des signes plus pour créer votre chaîne finale, mais il est préférable de le faire comme dans l'exemple qui est Null safe.

Cette procédure stockée produira (lancera) une erreur si vous fournissez des valeurs manquantes ou incorrectes, et vous ne serez pas autorisé à continuer. Il générera automatiquement une erreur si tous les numéros de séquence sont épuisés.

Votre procédure d'accès frontal doit vérifier qu'aucune erreur ne s'est produite, ce qui ne devrait se produire que si la séquence est à court de nombres, si vous fournissez des entrées de paramètres appropriées. Si une erreur est détectée, le frontal devra annuler son opération d'une manière ou d'une autre.

Il existe d'autres fonctionnalités que vous pouvez définir avec des arguments. CYCLE permettra à la séquence de refaire un cycle après avoir atteint la fin, puis d'aller à la MINVALUE. Vous pouvez même le redémarrer explicitement au milieu d'une séquence en lui donnant une valeur RESTART.

Vous pouvez également lui attribuer un CACHE, par exemple, vous pouvez demander 50 numéros de séquence à la fois, et il met à jour les tables de séquence du système une fois tous les 50 numéros, ce qui peut être plus rapide, mais cela ajoute également un risque en cas de panne de courant. , puisque ces numéros ne peuvent pas être réutilisés

La dernière chose à noter dans cette procédure stockée est que vous pouvez extraire des informations (métadonnées) sur vos séquences à partir d'une vue système appelée sys.sequences. Il contient les informations suivantes.


Certaines colonnes utiles que vous aimeriez lire et transmettre à un utilisateur sont minimum_value, maximum_value et valeur_actuelle.


Si vous êtes intéressé, les pages suivantes sur MSDN contiennent des informations très utiles sur les séquences.

Numéros de séquence
Décrit les séquences et contient de très bons exemples d'utilisation typique

CRÉER SÉQUENCE (Transact-SQL)

MODIFIER LA SÉQUENCE (Transact-SQL)

VALEUR SUIVANTE POUR (Transact-SQL)

sys.sequences (Transact-SQL)
Décrit les métadonnées que vous pouvez interroger sur vos séquences