Campo Sequencial / Incremental - RESOLVIDO com Dica do Haroldo

Prezados,
tenho a seguinte situação:

Tabela “Area” = AreaID, AreaNome
Tabela “AreaSetor” = AreaID, AreaSetorID, AreaSetorNome

No formulário (Insert) AreaSetor inicio com AreaID = variável que vem de um grid … ok
Já campo AreaSetorID quero que seja incrementado automaticamente observando a qual AreaID o mesmo pertence.
Utilizei a função de incremento manual do SC para o campo AreaSetorID, funciona mas o SC retorna a sequencia geral geral da tabela AreaSetor, sem observar o setor de cada área.

Fiz também uma tabela acessória só pra controlar este tipo de situação e associei uma rotina ao evento onBeforeInsert no formulário “AreaSetor”, a rotina de gravação na tabela acessória apurando o novo campo AreaSetorID funciona, porém não consigo fazer com que seja gravado na tabela AreaSetor (retorna msg dizendo que este campo deve ser preenchido - o campo AreaSetorID não deve ser apresentado na tela).

Exemplo das tabelas e como devo popular:

Area
AreaID, AreaNome
1 Norte
2 Sul
3 Leste

AreaSetor
AreaID, AreaSetorID, AreaSetorNome
1 1 Alfa
1 2 Beta
2 1 Central
2 2 Front
2 3 Beta

Agradeço qualquer dica.
Obrigado,

Utilize uma trigger before insert.

pegue o Max(AreaSetorID)+1 para o AreaID corrente e atribua ao AreaSetorID corrente.

Obrigado por responder Haroldo!
Sou novo no SC … trigger before insert você quer dizer evento onBeforeInsert?
Se for isso, foi ai mesmo que coloquei as instruções SQL, mas o SC não assume o novo valor para AreaSetorID.

Não. Trigger no banco diretamente sem envolver php.
Deixa o banco fazer isso.

Criar uma trigger na tabela AreaSetor do tipo before insert.

CREATE DEFINER=`root`@`%` TRIGGER `AreaSetor_before_insert` BEFORE INSERT ON `AreaSetor` FOR EACH ROW 
BEGIN
    DECLARE vAreaSetorId int;
  
    select CASE WHEN max(AreaSetorId) IS NULL 
                  THEN 1 
                  ELSE max(AreaSetorId)+1 
             END into vAreaSetorId  
    from AreaSetor 
    where AreaId=new.AreaId;
	
    set new.AreaSetorId = vAreaSetorId;
	
END

Exemplo na prática ->
Demonstração : Clique aqui

No caso: AreaId + AreaSetorId eu criei como índice composto único.

Se não tiver um campo id (pk autoincrement) terá dificuldades em fazer o formulário funcionar adequadamente.

Se houver necessidade de resequenciar AreaSetorId ao excluir registros intermediários use no evento onAfterdelete:

sc_exec_sql("SET @contador = 0;");
sc_exec_sql("UPDATE  AreaSetor  SET `AreaSetorId` = @contador := @contador + 1  where AreaId={AreaId}");
sc_commit_trans();

TAGS: Haroldo, Trigger, Banco, Dados, Formulário

Entendi Haroldo, vou tentar.
Obrigado,

Veja o exemplo.

Se houver necessidade de resequenciar AreaSetorId ao excluir registros intermediários use no evento onAfterdelete:

sc_exec_sql(“SET @contador = 0;”);
sc_exec_sql(“UPDATE AreaSetor SET AreaSetorId = @contador := @contador + 1 where AreaId={AreaId}”);
sc_commit_trans();

Saudações,

No meu caso preferi manter as regras de negócio na aplicação, sem “gatilhos” no banco.

Assim sendo. fiz uma biblioteca interna e fiz a função abaixo onde eu envio a empresa e o sistema atraves de uma tabela de sequencia incrementa o que ta e me retorna o campo já formatado.

function GetSeqEmpresa($P_Empresa, $P_Tabela,$P_Tamanho){
$Sequencia = ‘’;
$sql = “SELECT
sequencia
FROM a_sequencias
WHERE empresa = '”.$P_Empresa."’
AND tabela = ‘".$P_Tabela."’";
sc_lookup(rs_GetSeqEmpresa, $sql);
if(count({rs_GetSeqEmpresa}) == 0)
{
RETURN(“Erro não encontrado tabela “.$P_Tabela.” para empresa: “.$P_Empresa);
}
else
{
$Sequencia = {rs_GetSeqEmpresa[0][0]};
$sql = “Update a_sequencias set sequencia = '”.($Sequencia+1).”’
WHERE empresa = '”.$P_Empresa."’
AND tabela = ‘".$P_Tabela."’";
sc_lookup(rs_GetSeqEmpresa, $sql);
return($P_Empresa.str_pad($Sequencia,$P_Tamanho,“0”,STR_PAD_LEFT));
}
}

Esta funcionando beleza, apenas lembre-se de marcar sua aplicação para usar a biblioteca interna.

Espero ter ajudado.

Claudney

Além de um desperdício de memória e processamento extra há falha na questão multi-usuário nessa rotina.

Boa tarde Claudney e Haroldo,
agradeço pelas dicas para resolver.

Geraldo,

Coloque no tópico como resolvido, se caso resolvido e qual a solução adotada, para que o tópico não fique considerado como aberto.

Haroldo.
Ajude-nos ai, como mais experiente, vc tem mais visão, no meu caso, fiz essa função mas não tem nada em produção, até então me resolveu, qual o problema de multi-user ?
Achei melhor assim, pois se usar o SC e duas pessoas iniciarem dois registros e a primeira desistir o SC iria pular o número, então o que eu pensei no beforeinsert assim se alguém desistir sempre da certo.

Qual a sua sugestão, preciso melhorar a cada vez mais, (embora não tenho projeto em produção).

Grande abraço mestre.

Claudney

Vou explicar:

Em um sistema concorrente, duas telas distintas chamando a mesma aplicação pode ocorrer uma leitura (SELECT sequencia …) causando falha na implementação do sequencial.

Para melhorar um pouco essa questão usando sua rotina eu faria assim:

function GetSeqEmpresa($P_Empresa, $P_Tabela,$P_Tamanho){

      $sql = "Update a_sequencias set sequencia = sequencia +1
            WHERE empresa = '".$P_Empresa."'         
         AND tabela = '".$P_Tabela."'";
       sc_exec_sql($sql);
       sc_commit_trans();
   
   $sql = "SELECT 
         sequencia
            FROM a_sequencias 
            WHERE empresa = '".$P_Empresa."'
         AND tabela = '".$P_Tabela."'";
   sc_lookup(rs_GetSeqEmpresa, $sql);
   if(enpty({rs_GetSeqEmpresa})0) {
      RETURN("Erro não encontrado tabela ".$P_Tabela." para empresa: ".$P_Empresa);
   }
      else 
  {
   $Sequencia = {rs_GetSeqEmpresa[0][0]};
   return ($P_Empresa.str_pad($Sequencia,$P_Tamanho,"0",STR_PAD_LEFT));      
}
}

Mesmo assim isso seria colocado no evento onbeforeinsert para capturar o sequencial e gravar na tabela principal do formulário, mas caso haja falha no insert na tabela principal do formulário o update sequencial + 1 foi executado causando assim um salto no sequencial, ficando buracos na sequência.

Executando direto no banco você garante a segurança, pois se houver algum tipo de falha as instruções no banco não serão realizadas.

Bom dia.

Obrigado, Haroldo, vou testar.

Claudney

Olá Haroldo, boa tarde tudo bem. achei somente esta forma de entrar em contato com vc. Perdão pelo incômodo, mas poderia de dizer se conhece ou se existe alguma API para gerar Guia da Previdencia Social (Guia de GPS)?
Me chamo Carlos e ja trocamos anteriormente algumas mensagens. desde ja obrigado.

Nunca vi api para geração de GPS.

O que sei é que dá para gerar individualmente pelo app MeuINSS