Access
 sql >> Base de Dados >  >> RDS >> Access

Evite conflitos de número com sequências do Microsoft SQL

Evite conflitos de número com sequências do Microsoft SQL




Observação:apresentarei este tópico no grupo Access with SQL Server online. Junte-se a mim no dia 13 de setembro às 18h30 CST, junte-se ao grupo para receber um e-mail com todos os detalhes da reunião, é grátis!
  • Você precisa garantir que um número em um campo será usado apenas uma vez e nunca será duplicado por outro usuário?
  • Você já teve uma situação em que precisou de mais de uma numeração automática em uma tabela?
  • Você já precisou de um limite inferior e superior de números sequenciais e não conseguiu ir além disso?
  • Às vezes, você tem uma lista de números que deseja reciclar depois de passar do último?

No SQL Server, há um recurso que pode lidar com isso com bastante facilidade e é chamado de sequência. Está disponível a partir do SQL Server 2012.

Como um número automático, ele pode garantir que um número único seja dado a cada vez, a menos que seja reciclado.

Recentemente me pediram para implementar uma sequência para um cliente, onde vários usuários criariam novos registros e teriam que “buscar” o próximo número em uma sequência específica. Não foi possível usar um número automático porque o cliente estava limitado a um determinado intervalo, para não exceder um limite superior. Quando os números se esgotassem, a administração reabastecia a sequência novamente.

Por que usar uma tabela do Access não funciona


Antes de atualizar para o SQL Server, os usuários compartilhariam uma tabela que manteria guias sobre qual é o próximo número a ser usado, o problema com essa abordagem é que não é infalível, dois usuários podem solicitar o mesmo número exatamente ao mesmo tempo, violando a regra de negócio.

Criando e usando uma sequência do SQL Server


Antes de poder usar uma sequência, ela deve ser criada com a seguinte sintaxe no SQL Server, você só precisa fazer isso uma vez:
CREATE SEQUENCE dbo.seqPolicyNumber AS int MIN 50005000 MAX 50005999;
Use a seguinte instrução para recuperar o próximo número de sequência:
SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue
Seus usuários precisarão de permissões de atualização para usar a sequência, mas não poderão alterar o intervalo da sequência. Permissões de atualização podem ser fornecidas usando esta sintaxe:
GRANT UPDATE ON dbo.seqPolicyNumber TO [MyDatabaseUserOrRole];
Para obter o próximo valor de uma sequência de um programa VBA do Microsoft Access, você pode usar a instrução a seguir para ler o próximo valor em um conjunto de registros ADODB.
strSQL = "SELECT NEXT VALUE FOR dbo.seqPolicyNumber as NextValue"
OpenMyRecordset rs, strSQL
NextValue = rs("NextValue")

É assim que normalmente abrimos um conjunto de registros ADODB em nossa empresa. Para mais informações sobre como você pode usar o OpenMyRecordset, você pode clicar em outro artigo em nosso blog:

Conjuntos de registros e comandos fáceis do ADODB no acesso

O bom da sintaxe para obter o próximo número de sequência é que é muito fácil de usar em T-SQL. Você apenas substitui NEXT VALUE FOR onde normalmente obteria um valor de um nome de campo, parâmetro ou uma constante. Veja a seguir como ele pode ser usado em uma instrução Insert.
INSERT dbo.Orders (OrderID, Name, Qty)
VALUES (NEXT VALUE FOR dbo.OrderNumberSequence, 'Tire', 2);

Mais flexibilidade do que Autonumber


Uma sequência pode oferecer mais flexibilidade do que uma numeração automática no Access ou um campo IDENTIDADE no SQL Server. Primeiro, você só pode ter um campo de numeração automática ou de identidade em uma tabela. Embora você possa propagar novamente um campo IDENTITY, não é possível reciclar valores. Os campos IDENTITY ainda são úteis para chaves primárias, quando queremos que algum número arbitrário identifique o registro, e isso não tem significado. Os intervalos de sequências, no entanto, podem ter significado incorporado.

Você também não está restrito a usar números inteiros como uma IDENTIDADE, mas os números de sequência também podem ser decimais ou numéricos. Além disso, você pode incrementar para baixo em sua sequência em vez de apenas para cima.

Além disso, uma sequência não está vinculada a nenhuma tabela específica e pode ser usada em tabelas, pois novos números de sequência são necessários para uma tabela específica.

Reabasteça a sequência


Quando você deseja alterar o intervalo de uma sequência, como quando precisa de um novo intervalo de números de política, isso deve ser feito com um procedimento armazenado. Veja a seguir um procedimento armazenado que pode fazer isso.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


CREATE PROCEDURE [dbo].[usp_AlterPolicySequence] (
@SeqName AS sysname,
@InpMin AS int,
@InpMax AS int
) WITH EXECUTE AS OWNER AS
BEGIN
SET NOCOUNT ON;

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

SE NÃO EXISTE (
SELECT NULL
FROM sys.sequences AS s
WHERE s.name =@SeqName
AND s.schema_id =SCHEMA_ID('dbo')
)
THROW 50000, 'O nome da sequência não é válido.', 1;

IF @InpMin É NULO OU @InpMax É NULO
THROW 50000, 'Os valores não podem ser nulos.', 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' SEM CICLO SEM CACHE;');
EXEC sys.sp_executesql @sql;

;

FIM

Há algumas coisas dignas de nota neste procedimento armazenado. Primeiro estamos executando
COM EXECUTE AS OWNER AS.

Não queremos que o usuário comum possa alterar uma sequência. Mas queremos dar a eles capacidade limitada de alterá-lo apenas por meio de um procedimento armazenado. (Os usuários só precisam de direitos para o procedimento armazenado.)
GRANT EXECUTE ON dbo.usp_AlterPolicySequence TO [MyDatabaseUserOrRole];
Este procedimento armazenado pode ser executado a partir de um front end do Access, sempre que um novo intervalo na sequência precisar ser instalado, e isso normalmente seria por um usuário administrador, que pode ter mais privilégios do SQL Server do que um usuário normal.

No entanto, esse procedimento armazenado também pode ser executado quando um novo intervalo de números está aguardando para ser carregado na sequência, logo após a sequência atual ser usada. Nesse caso, o procedimento armazenado pode ser chamado por qualquer usuário que precise do primeiro número de política para o novo intervalo. Portanto, usamos WITH EXECUTE AS OWNER AS para dar a eles mais direitos apenas para esse uso limitado.

Outra coisa a notar é que é necessário construir uma string SQL, e então usar
EXEC sys.sp_executesql


nessa string, se estivermos usando parâmetros.

A instrução a seguir funcionará se for digitada em uma janela de consulta do SSMS ou usada em um procedimento armazenado.

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

No entanto, o seguinte não funcionará usando parâmetros em um procedimento armazenado.
ALTER SEQUENCE dbo.seqPolicyNumber
RESTART WITH @InpMin
INCREMENT BY 1
MINVALUE @InpMin
MAXVALUE @InpMax
NO CYCLE
NO CACHE

Então você precisa construir a instrução string com os valores dos parâmetros colados.
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;
Essa string @sql é construída usando as funções CONCAT e QUOTENAME. Também funcionará se você usar sinais de adição para fazer sua string final, mas é melhor fazê-lo como o exemplo que é Null safe.

Esse procedimento armazenado produzirá (lançará) um erro se você fornecer valores ausentes ou incorretos e não poderá continuar. Ele gerará automaticamente um erro se todos os números de sequência forem usados.

Seu procedimento de acesso de front-end deve verificar se não ocorreu um erro, o que deve ocorrer apenas se a sequência ficar sem números, se você estiver fornecendo entradas de parâmetro adequadas. Se um erro for visto, o front-end precisará cancelar sua operação de alguma forma.

Existem alguns outros recursos que você pode definir com argumentos. CYCLE permitirá que a sequência refaça o ciclo novamente após atingir o final e, em seguida, vá para o MINVALUE. Você pode até mesmo reiniciá-lo explicitamente no meio de uma sequência, dando-lhe um valor RESTART.

Você também pode dar um CACHE, por exemplo, você pode pedir 50 números de sequência por vez, e ele atualiza as tabelas de sequência do sistema uma vez a cada 50 números, o que pode ser mais rápido, mas também adiciona um risco se houver uma falha de energia , uma vez que esses números não podem ser reutilizados

A última coisa que vale a pena notar neste procedimento armazenado é que você pode extrair informações (metadados) sobre suas sequências de uma exibição do sistema chamada sys.sequences. Ele contém as seguintes informações.


Algumas colunas úteis que você pode querer ler e transmitir a um usuário são valor_mínimo, valor_máximo e valor atual.


Se você estiver interessado, as seguintes páginas do MSDN têm informações muito úteis sobre sequências.

Números de Sequência
Descreve sequências e tem exemplos muito bons para uso típico

CRIAR SEQUÊNCIA (Transact-SQL)

ALTER SEQUENCE (Transact-SQL)

PRÓXIMO VALOR PARA (Transact-SQL)

sys.sequences (Transact-SQL)
Descreve os metadados que você pode consultar em suas sequências