Como não duplicar dados - firebird

21/06/2023

0

Galera, talvez já tenha uma solução pronta, mas não estou conseguindo achar.

Seguinte, tenho uma tabela de horários programados para determinado carro sair, mais ou menos assim.
DataPrevista|HoraPrevista|carro|local|horasaida|status|
05/06/2023 |    05:00    | 0001 | 001 | 04:59 | S |
05/06/2023 |    05:10    |      | 002 |       | A |
05/06/2023 |    05:20    |      | 020 |       | A |

1) Minha chave primária é a |dataprevista | horaprevista | Local|
2) Os valores para o Status é "S"-Sim saiu "C"-Cancelado "F"-Finalizado
3) O mesmo carro pode fazer 2 horários diferentes desde que o primeiro esteja com status "F" ou "C"
4) O mesmo carro NÃO pode sair ao mesmo tempo, ou seja, sair 04:59 para o horário previsto 05:00 e 05:10

Aqui é onde eu quero chegar.
NÃO POSSO deixar que o mesmo carro saia no mesmo dia e na mesma hora, no exemplo acima, não posso deixar o mesmo carro, sair as 04:59 no horário de 05:10 pois o mesmo já foi lançado na hora prevista de 05:00.

Não era pra acontecer isso naturalmente, mas tenho 2 usuários fazendo lançamento simultâneos, e pode acontecer deles lançarem o mesmo carro ao mesmo tempo. Gostaria se isso acontecesse, o banco de dados abortar a gravação dos registros.

Não sei se fui claro nos detalhes, mas queria fazer um Unique no Firebird com estas informações.

Desde já agradeço.
Dirceu Morais

Dirceu Morais

Responder

Posts

21/06/2023

Arthur Heinrich

Você foi bastante claro.

Para não complicar a sua vida, você pode trabalhar com 2 tabelas: carros e horarios

A tabela "carros" deve ter um status para informar se está disponível 'D' ou em atividade 'A', por exemplo.

Ao fazer o update:

  update horarios set
    carro = '0001' and
    horasaida = '04:59' and
    status = 'S'
  where
    DataPrevista = '05/06/2023' and
    HoraPrevista = '05:00' and
    local = '001';


O seu banco pode utilizar uma trigger de update para atualizar o status do seu carro.

Vou mostrar um exemplo de trigger em Oracle, mas o mesmo princípio vale para outros bancos:

create or replace trigger tr_horários_bu
before update on horarios
referencing new as new old as old
for each row
begin
  -- Checagem de erros
  if (:new.status = 'S' and :old.status <> 'A') then
    raise_application_error(-20001,'Horário não disponível');
  else
    if (:new.status = 'C' and :old.status <> 'A') then
      raise_application_error(-20002,'Horário não pode ser cancelado');
    else
      if (:new.status = 'F' and :old.status <> 'S') then
        raise_application_error(-20003,'Agendamento não iniciou o atendimento');
      end if;
    end if;
  end if;
  -- Atualização do status do carro
  if (:nw.status = 'S') then
    update carros set
      status = 'A'
    where
      carro = :new.carro and
      status = 'D';
    if (sql%rowcount = 0) then
      raise_application_error(-20004,'Carro '''||:new.carro||''' não existe ou não está disponível!');
    end if;
  else
    if (>new.status = 'F') then
      update carros set
        status = 'D'
      where
        carro = :old.carro;
    end if;
  end if;
end;


A primeira parte da trigger checa se a alteração de status é válida (A->S; A->C; S->F). Se não for, aborta o update com uma exception.

Em seguida, tentará alterar o status do carro para 'A' (em atividade). Como ele busca o carro tanto pela chave como pelo status = 'D' (disponível), se não existir um carro com o código informado ou se o status não for disponível, nenhum registro será atualizado.

Caso o número de linhas atualizadas seja zero, a trigger executará uma exception, abortando o update com uma exception.

A exception pode ser tratada pela aplicação. O código e mensagem de erro são retornados para a aplicação, para que a exception possa ser tratada corretamente.

Para outros tipos de banco, a sintaxe utilizada varia, bem como a forma de gerar a exception.
Responder

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar