sql >> Base de Datos >  >> RDS >> Access

Evite conflictos de números con secuencias de Microsoft SQL

Evite conflictos de números con secuencias de Microsoft SQL

Nota:Presentaré este tema en el grupo de Access con SQL Server en línea. Únase a mí el 13 de septiembre a las 6:30 p. m. CST, únase al grupo para recibir un correo electrónico con todos los detalles de la reunión, ¡es gratis!

  • ¿Necesita garantizar que un número en un campo solo se usará una vez y nunca será duplicado por otro usuario?
  • ¿Ha tenido una situación en la que necesitaba más de un número automático en una tabla?
  • ¿Alguna vez ha necesitado un límite superior e inferior de números secuenciales y no pudo ir más allá?
  • ¿A veces tienes una lista de números que quieres reciclar después de pasar el último?

En SQL Server, hay una función que puede manejar esto con bastante facilidad, y se llama secuencia. Está disponible a partir de SQL Server 2012.

Al igual que un número automático, puede garantizar que se dará un número único cada vez, a menos que se recicle.

Recientemente me pidieron que implementara una secuencia para un cliente, donde múltiples usuarios crearán nuevos registros y tendrán que "obtener" el siguiente número en una secuencia específica. No podíamos usar un número automático porque el cliente estaba limitado a un cierto rango, sin exceder un umbral superior. Cuando se agotaron los números, la gerencia reponía la secuencia nuevamente.

Por qué usar una tabla de Access no funciona

Antes de actualizar a SQL Server, los usuarios compartían una tabla que controlaba cuál es el siguiente número a usar, el problema con este enfoque es que no es infalible, dos usuarios pueden solicitar el mismo número exactamente al mismo tiempo, violando la regla de negocio.

Creación y uso de una secuencia de SQL Server

Antes de poder usar una secuencia, debe crearse con la siguiente sintaxis en SQL Server, solo necesita hacer esto una vez:
CREATE SEQUENCE dbo.seqPolicyNumber AS int MIN 50005000 MAX 50005999;
Utilice la siguiente instrucción para recuperar el siguiente número de secuencia:
SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue
Sus usuarios necesitarán permisos de actualización para usar la secuencia, pero no deberían poder modificar el rango de la secuencia. Se pueden otorgar permisos de actualización usando esta sintaxis:
GRANT UPDATE ON dbo.seqPolicyNumber TO [MyDatabaseUserOrRole];
Para obtener el siguiente valor de una secuencia de un programa VBA de Microsoft Access, puede usar la siguiente declaración para leer el siguiente valor en un conjunto de registros ADODB.
strSQL = "SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue"
OpenMyRecordset rs, strSQL
NextValue = rs("NextValue")

Así es como normalmente abrimos un conjunto de registros ADODB en nuestra empresa. Para obtener más información sobre cómo puede utilizar OpenMyRecordset, puede hacer clic en otro artículo de nuestro blog:

Comandos y conjuntos de registros ADODB sencillos en Access

Lo bueno de la sintaxis para obtener el siguiente número de secuencia es que es muy fácil de usar en T-SQL. Simplemente sustituya PRÓXIMO VALOR POR donde normalmente obtendría un valor de un nombre de campo, parámetro o una constante. A continuación, se muestra cómo se puede usar en una instrucción Insert.
INSERT dbo.Orders (OrderID, Name, Qty)
VALUES (NEXT VALUE FOR dbo.OrderNumberSequence, 'Tire', 2);

Más flexibilidad que la numeración automática

Una secuencia puede ofrecer más flexibilidad que una numeración automática en Access o un campo de IDENTIDAD en SQL Server. En primer lugar, solo puede tener un campo de autonumeración o de identidad en una tabla. Aunque puede reinicializar un campo IDENTIDAD, no puede reciclar valores. Los campos de IDENTIDAD siguen siendo útiles para las claves primarias, cuando queremos que algún número arbitrario identifique el registro y no tiene ningún significado. Sin embargo, los rangos de secuencias pueden tener un significado incrustado.

Tampoco está restringido a usar números enteros como una IDENTIDAD, pero los números de secuencia también pueden ser decimales o numéricos. También puede incrementar hacia abajo en su secuencia en lugar de solo hacia arriba.

Además, una secuencia no está vinculada a ninguna tabla específica y se puede usar entre tablas, ya que se necesitan nuevos números de secuencia para una tabla en particular.

Reponer la Secuencia

Cuando desee cambiar el rango de una secuencia, como cuando necesita un nuevo rango de números de póliza, debe hacerlo con un procedimiento almacenado. El siguiente es un procedimiento almacenado que puede hacer esto.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREAR PROCEDIMIENTO [dbo].[usp_AlterPolicySequence] (
@SeqName AS sysname,
@InpMin AS int,
@InpMax AS int
) CON EJECUTAR COMO PROPIETARIO COMO
COMENZAR
ESTABLECER SIN CUENTA EN;

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

SI NO EXISTE (
SELECCIONE NULL
DESDE sys.sequences COMO s
DONDE s.name =@SeqName
Y s.schema_id =SCHEMA_ID('dbo')
)
THROW 50000, 'El nombre de la secuencia no es válido.', 1;

SI @InpMin ES NULO O @InpMax ES NULO
THROW 50000, 'Los valores no pueden ser nulos', 1;

SET @sql =CONCAT(N'ALTER SEQUENCE [dbo].', QUOTENAME(@SeqName), N' REINICIAR CON ', @InpMin, N' INCREMENT BY 1′, N' MINVALUE ', @InpMin, N' MAXVALUE ' , @InpMax, N' SIN CICLO SIN CACHE;');
EXEC sys.sp_executesql @sql;

;

FIN

Hay algunas cosas que vale la pena señalar en este procedimiento almacenado. Primero lo estamos ejecutando
CON EJECUTAR COMO PROPIETARIO AS.

No queremos que el usuario cotidiano pueda alterar una secuencia. Pero queremos darles una capacidad limitada para modificarlo solo a través de un procedimiento almacenado. (Los usuarios solo necesitan derechos sobre el procedimiento almacenado).
GRANT EXECUTE ON dbo.usp_AlterPolicySequence TO [MyDatabaseUserOrRole];
Este procedimiento almacenado se puede ejecutar desde un front-end de Access, siempre que sea necesario instalar un nuevo rango en la secuencia, y eso normalmente lo haría un usuario administrador, que podría tener más privilegios de SQL Server que un usuario normal.

Sin embargo, este procedimiento almacenado también podría ejecutarse cuando un nuevo rango de números está esperando para cargarse en la secuencia, justo después de que se agote la secuencia actual. En este caso, cualquier usuario que necesite el primer número de póliza para el nuevo rango podría llamar al procedimiento almacenado. Así que usamos WITH EXECUTE AS OWNER AS para otorgarles más derechos solo para este uso limitado.

Otra cosa a tener en cuenta es que es necesario construir una cadena SQL y luego usar
EXEC sys.sp_executesql

en esa cadena, si estamos usando parámetros.

La siguiente declaración funcionará si se escribe en una ventana de consulta de SSMS o si se usa en un procedimiento almacenado.

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

Sin embargo, lo siguiente no funcionará usando parámetros en un procedimiento almacenado.
ALTER SEQUENCE dbo.seqPolicyNumber
RESTART WITH @InpMin
INCREMENT BY 1
MINVALUE @InpMin
MAXVALUE @InpMax
NO CYCLE
NO CACHE

Por lo tanto, debe construir la sentencia de cadena con los valores de los parámetros pegados.
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;
Esta cadena @sql se construye usando las funciones CONCAT y QUOTENAME. También funcionará si usó signos más para hacer su cadena final, pero es mejor hacerlo como el ejemplo que es seguro para nulos.

Este procedimiento almacenado producirá (arrojará) un error si proporciona valores incorrectos o faltantes, y no podrá continuar. Generará automáticamente un error si se agotan todos los números de secuencia.

Su procedimiento de acceso frontal debe verificar que no haya ocurrido un error, lo que solo debería ocurrir si la secuencia se queda sin números, si está proporcionando las entradas de parámetros adecuadas. Si se ve un error, entonces el front-end deberá cancelar su operación de alguna manera.

Hay algunas otras capacidades que puede configurar con argumentos. CYCLE permitirá que la secuencia vuelva a realizar un ciclo después de que llegue al final, y luego irá al MINVALUE. Incluso puede reiniciarlo explícitamente en medio de una secuencia dándole un valor de REINICIO.

También puede darle un CACHE, por ejemplo, puede solicitar 50 números de secuencia a la vez, y actualiza las tablas de secuencia del sistema una vez cada 50 números, lo que puede ser más rápido, pero también agrega un riesgo si hay una falla de energía. , ya que estos números no se pueden reutilizar

Lo último que vale la pena señalar en este procedimiento almacenado es que puede extraer información (metadatos) sobre sus secuencias desde una vista del sistema llamada sys.sequences. Contiene la siguiente información.


Algunas columnas útiles que le gustaría leer y transmitir a un usuario son valor_mínimo, valor_máximo y valor_actual.


Si está interesado, las siguientes páginas en MSDN tienen información muy útil sobre secuencias.

Números de secuencia
Describe secuencias y tiene muy buenos ejemplos para uso típico

CREAR SECUENCIA (Transact-SQL)

ALTERAR SECUENCIA (Transact-SQL)

PRÓXIMO VALOR PARA (Transact-SQL)

sys.sequences (Transact-SQL)
Describe los metadatos que puede consultar en sus secuencias