Pergunta

Eu estou procurando a melhor maneira de ir sobre a adição de uma restrição a uma tabela que é efetivamente um índice exclusivo sobre a relação entre o registro e o resto dos registros na tabela.

Imagine a seguinte tabela descrevendo as patrulhas de vários guardas (do cenário vigia anterior)

PK  PatrolID Integer
FK  GuardID  Integer
    Starts   DateTime
    Ends     DateTime

Começamos com uma restrição especificando que os horários de início e de término deve ser lógico:

Ends >= Starts

No entanto eu quero adicionar outro constrangimento lógico: Um específico de guarda (GuardID) não pode estar em dois lugares ao mesmo tempo, o que significa que para qualquer registro do período especificado pelo Start / extremidades devem não sobreposição com o período definido para qualquer outra patrulha pelo mesmo guarda.

Eu posso pensar de duas maneiras de tentar abordar esta:

Criar um VEZ DE INSERÇÃO gatilho. Esse gatilho, então, usar cursores para percorrer a tabela inserida, verificando cada registro. Se qualquer registro em conflito com um registro existente, um erro seria levantado. Os dois problemas que tenho com esta abordagem são: Eu não gosto de utilizar cursores em uma versão moderna do SQL Server, e eu não tenho certeza de como ir sobre implimenting a mesma lógica para atualizações. Também pode haver a complexidade dos registros dentro INSERTED conflitantes entre si.

O segundo, aparentemente melhor, a abordagem seria criar uma restrição que chama uma função definida pelo usuário, passando os PatrolID, GuardID, começa e termina. A função, então, fazer uma ONDE EXISTE consulta de verificação para todos os registros que se sobrepõem as / inicia / termina parâmetros GuardID que não são o registro PatrolID originais. No entanto, eu não tenho certeza do que potenciais efeitos colaterais esta abordagem possa ter.

É a segunda melhor abordagem? Alguém vê as armadilhas, como quando inserir / atualizar várias linhas de uma vez (aqui eu estou preocupado porque linhas dentro desse grupo poderia entrar em conflito, ou seja, a ordem em que são "inserido" faz a diferença). Existe uma melhor maneira de fazer isso (como algum truque fantasia INDEX?)

Foi útil?

Solução

Use um depois gatilho para verificar se a restrição de sobreposição não foi violada:

create trigger Patrol_NoOverlap_AIU on Patrol for insert, update as
    begin
    if exists (select *
        from inserted i
        inner join Patrol p
            on i.GuardId = p.GuardId
            and i.PatrolId <> p.PatrolId
        where (i.Starts between p.starts and p.Ends)
        or (i.Ends between p.Starts and p.Ends))

        rollback transaction
    end

NOTA: reverter uma transação dentro de um gatilho irá terminar o lote. Ao contrário de uma violação contraint normal, você não será capaz de capturar o erro.

Você pode querer um diferente onde cláusula dependendo de como você define o intervalo de tempo e se sobrepõem. Por exemplo, se você quer ser capaz de dizer Guarda # 1 está em X 6:00 - 07:00 então Y 7:00 para 8:00 o acima não permitiria. Você gostaria em vez disso:

create trigger Patrol_NoOverlap_AIU on Patrol for insert, update as
    begin
    if exists (select *
        from inserted i
        inner join Patrol p
            on i.GuardId = p.GuardId
            and i.PatrolId <> p.PatrolId
        where (p.Starts <= i.Starts and i.Starts < p.Ends)
        or (p.Starts <= i.Ends and i.Ends < p.Ends))

        rollback transaction
    end

Onde Starts é o momento os que guardam começa e termina é o momento infinitesimal depois guardando extremidades.

Outras dicas

A maneira mais simples seria usar um procedimento armazenado para as inserções. O procedimento armazenado pode fazer a inserção em uma única instrução:

insert into YourTable
(GuardID, Starts, Ends)
select @GuardID, @Starts, @Ends
where not exists (
    select *
    from YourTable
    where GuardID = @GuardID
    and Starts <= @Ends
    and Ends >= @Start
)

if @@rowcount <> 1
    return -1 -- Failure

Em minha experiência, gatilhos e restrições com UDF de tendem a se tornar muito complexo. Eles têm efeitos colaterais que podem exigir um monte de depuração para descobrir.

Os procedimentos armazenados apenas trabalho, e eles têm a vantagem adicional de que você pode negar permissões INSERT para clientes, dando-lhe o controle refinado sobre o que entra no seu banco de dados.

CREATE TRIGGER [dbo].[emaill] ON [dbo].[email]
FOR INSERT

AS

BEGIN


    declare @email CHAR(50);


    SELECT @email=i.email from inserted i;

    IF @email NOT LIKE '%_@%_.__%' 
    BEGIN
            print 'Triggered Fired';
            Print 'Invalid Emaill....';
            ROLLBACK TRANSACTION
    END 

END
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top