12
respostas

Clonar ID da PK para a FK

Tenho duas tabelas, a primeira tem pk com auto_increment, e quero que a segunda, tenha a fk com os mesmos valores da pk. Mas quando consulto os valores da fk da segunda tabela está nulo, como eu faço para que a fk da segunda tabela copie os valores da pk da primeira tabela? alguém sabe como fazer isso?

CREATE TABLE PRIMEIRA_TABELA(
ID_DESPESA INT(144) NOT NULL AUTO_INCREMENT,
DESCRICAO VARCHAR(144),
PRIMARY KEY (ID_DESPESA)
);

CREATE TABLE SEGUNDA_TABELA(
    ID_HISTORICO INT(144) AUTO_INCREMENT,
    ID_DESPESA VARCHAR(144),
    DATAS VARCHAR(144),
    VALOR_DESPESA VARCHAR(144),
    PRIMARY KEY (ID_HISTORICO),
    FOREIGN KEY (ID_DESPESA) REFERENCES TIPO_DESPESA (ID_DESPESA)
);
12 respostas

Oi Ronaldo!

Isso você mesmo precisa fazer na hora de fazer os inserts no seu banco. Ou seja, na hora de inserir um elemento na segunda tabela, você precisa colocar o valor da pk na primeira tabela.

abraços!

Olá Ronaldo,

Além do que o Philippe falou, talvez fosse bacana também você ter na SEGUNDA_TABELA o id_despesa sendo INT(144) (como na PRIMEIRA_TABELA).

Também ver a possibilidade de DATAS na SEGUNDA_TABELA ser do tipo DATETIME (ou DATE), ao invés de VARCHAR. Poderia economizar tempo com algumas validações assim, e a chance de entrar um dado em sua tabela que não fosse data nesta coluna seria bem menor.

Mesmo esquema com VALOR. Se for um dado monetário, por exemplo, declará-lo como NUMBER com casas decimais, o que também poderia te poupar algumas validações a fim de checar dados espúrios.

Caso o ID da despesa seja obrigatório para o histórico, a coluna ID_DESPESA pode ser NOT NULL na SEGUNDA_TABELA. O mesmo vale para DATAS e VALOR_DESPESA.

Abraço.

outra coisa bem importante a colocar (ON DELETE CASCADE ON UPDATE CASCADE). para quando apagar um registro da primeira tabela o segunda ficar referenciando uma fk que não existe mais.

Sim, Davi. De fato, isso é algo a ser analisado e tem duas vantagens: manter consistência da base e dar a possibilidade de ela crescer em um ritmo menor, poupando espaço de armazenamento.

Contudo, talvez não seja interessante neste caso o "ON DELETE CASCADE", porque a segunda tabela é de histórico, logo, dependendo da regra de negócio, pode-se querer que os registros existam como histórico mesmo não havendo os registros-pais na primeira tabela.

Talvez o Ronaldo possa esclarecer isso, já que provavelmente está mais a par da regra de negócio.

Abraço.

Olá Ronaldo,

Essa associação automática que você está querendo não tem como ser feita, somente dentro da sua aplicação você conseguirá fazer esta associação. Ou seja essa associação só é possível de forma manual.

Olá Ronaldo,

Considerando o que o Fábio disse, se você puder alterar a estrutura do banco, pode usar uma trigger para, inserindo na primeira tabela, inserir na segunda também:

https://dev.mysql.com/doc/refman/5.7/en/trigger-syntax.html

https://pt.stackoverflow.com/questions/22754/como-criar-uma-trigger-mysql-para-dar-baixa-no-estoque

Caso você não possa alterar nada no banco, de fato você tem que fazer as inserções nas duas tabelas via aplicação.

Abraço!

Rafael Franco Rosa ,

Eu não recomendaria a utilização de triggers em nenhum caso quando se refere a regra de negócios. Tudo que você faz com triggers você consegue fazer dentro de métodos , procedures e etc... As tirggers criam uma dependência perigosa e de difícil manutenção pois ficam "escondidas", fazendo com que se seu projeto vire um caos. Além de problemas gravíssimos de implementação que podem ocorrer dificultando o rastreamento do mesmo. Definitivamente esta é uma péssima pratica de desenvolvimento de BD.

De fato, com trigger você tem algo mais implícito, mas como o Ronaldo está começando com MySQL, talvez seja uma boa conhecer este recurso também.

Além disso, caso haja uma modelagem correta da base, não vejo a princípio tantos problemas. Talvez você possa discorrer mais sobre isso.

Uma vantagem de não acoplar tanto as inserções à aplicação é que o desenvolvedor não precisa se preocupar com ordem de inserção nas tabelas, nem todas as restrições relativas a possíveis dados espúrios, programando mais OO, por exemplo, do que tendo que pensar na base de dados.

Rafael,

O principal problema é o de manutenção. Como a trigger é um código implícito muitas vezes quando se dá manutenção em um sistema as triggers sempre são esquecidas. Sempre é melhor deixar o código explicito para que a manutenção seja facilitada. Quando você tem um sistema pequeno a manutenção não parece ser um problema , mas em sistemas muito grandes posso de garantir por experiência de mais de 15 anos com desenvolvimento de banco de dados e como DBA que triggers causam um problema seríssimo de manutenção. Outra coisa são implementações que podem gerar erros difíceis de rastrear. Por exemplo: você tem uma trigger que gera um log em txt toda vez antes de uma tabela ser atualizada. Vamos dizer que no meio da transação ocorra um erro, o rollback é realizado na tabela, porém o log é gerado dizendo que a tabela foi atualizada dando um sinal errado para quem acompanha os logs do sistemas não evidenciando o erro ocorrido, pois não há como dar rollback em um arquivo txt. Se esse trecho de código fosse escrito dentro da própria procedure, package , método e etc isso nunca iria acontecer.

Sim, Fábio. Mas, se está havendo manutenção no sistema, tudo deve ser analisado, certo?

Desde a aplicação até a base de dados.

Claro, ao centralizar pontos, vai ter mais facilidade em manter, o que é algo a se pensar sobretudo em aplicaçẽos novas.

Contudo, sabemos que há sistemas que estão rodando há anos, às vezes décadas, então temos que saber que podem haver coisas legadas, logo elas também devem ser analisadas. Como você mencionou 'experiência', deve concordar que mexer em coisas legadas é (quase) sempre um vespeiro.

Sobre as implementações que geram erros difíceis de rastrear, isso pode ocorrer mesmo tendo coisas mais na aplicação.

Quando você mencionou a trigger que gera um arquivo, já consegui ver um erro: de haver o log do sucesso, mas não o log de erro (ou seja, no caso de rollback, logar que houve algo inesperado). Neste caso, é mais erro de arquitetura do que problema na trigger, ou seja, erro de não prever o caminho não-feliz e saber que isso devia estar num nível acima da trigger.

O ponto é , sem usar trigger você nunca iria gerar um log de sucesso indevido. Só dei um exemplo, mas é para salientar que utilizando triggers você corre esse risco, além de não obter nenhuma vantagem a mais de desenvolvimento. Ou seja o custo benefício não vale a pena. Mas se você acha uma boa utilizar... Só estou dando minha opinião de muitos anos de experiência em diversos projetos onde tive problemas com triggers, e não só sou eu que tenho esse tipo de opinião. Tom Kyte "papa" do Oracle também compartilha da mesma opinião. Mas opinião cada um tem a sua, como disse , se você acha que é uma boa solução para seu projeto...

Sim, com a trigger não tem como gerar log de rollback mesmo.

Mas vi que o risco maior é de arquitetura, planejamento, não exatamente de usar trigger.

Creio que, como tudo em TI, depende. Tem situações que pode ser uma boa usar trigger, outras não. Assim como usar ou não banco relacional, usar ou não uma determinada linguagem de programação e por aí vai.

Complementando sua última frase: não há bala de prata em TI; tudo deve ser avaliado. Não dá para usar algo só porque foi recém-lançado ou deixar de usar só porque alguém falou que não é bom, já que um determinado item pode não ser bom para dados contextos, mas pode fazer sentido em outros.