Array
(
)

Inserir registo em tabela com chave estrangeira

Maria Araújo
   - 08 mai 2014

Olá.
Estou com uma dúvida na inserção em uma tabela.
Tenho a tabela Cliente com o atributo IdCodPostal, que é chave estrangeira para a tabela CodPostal.
A tabela CodPostal tem como chave primária IdCodpostal. Tem ainda mais um atributo, Localidade.
Ao inserir um Cliente, quando for preencher o campo IdCodPostal esse valor já teve estar incluido na tabela CosPostal, pois é uma chave estrangeira.
Mas o que eu queria era que quando cadastrasse um Cliente pudesse preencher o campo IdCodPostal e Localidade. Mas como Localidade é atributo de outra tabela não sei bem como fazer. Além disso queria que, ao cadastrar, se o valor de IdCodPostal não estivesse na tabela CodPostal ele fosse automaticamente inserido lá, bem como a respetiva Localidade.
Obrigado

João Antonio
|
MVP
Pontos: 120
    08 mai 2014

Bom dia Maria,

A sua estrutura esta correta, você quer informar ao usuário o nome da localidade, para fazer isso tem que fazer um select quando o usuário seleciona o IdCodpostal da chave estrangeira e exibir no campo para visualização.
Dessa forma você não vai ter anomalias de dados.

Exemplo.

select * from CodPostal where IdCodpostal=:IdCodpostal

Att
João Antonio

Maria Araújo
   - 12 mai 2014

Mas imagine que eu estou a cadatrar o Cliente A.
Introduzo os seus dados e ele tem CodPostal AAAA e Localidade BBBB.
Se este registo de CodPostal não estiver já inserido na tabela CodPostal, vou ter um erro, por causa da chave estrangeira.
Eu penso que devo fazer uma procedure para inserir Cliente e, quando preencher o IdCodPostal no Cliente tenho de ir confirmar à tabela CodPostal se esse IdCodPostal já está inserido ou não.
Se já estiver não há problema.
O problema é se o IdCodPostal AAAA não está na tabela CodPostal.
Devo criar um trigger para quando inserir um IdCodPostal, que não esteja na Tabela CodPostal, ele chame a procedure de inserir CodPostal, com IdCospPostal e Localidade?
Acho que está um pouco confuso não?

Jair A.n.
   - 12 mai 2014

Bom Dia, não tem como, você deverá fazer a inclusão na tabela de relacionamento para depois, ai sim preencher a sua principal para não ter registros "órfãos" dando erro de chave não encontrada, faça um procedimento primeiro de inclusão nas tabelas de relacionamento, após esse procedimento não terá mais problemas, caso contrário sua segunda opção será criar um processo com os procedimentos de pesquisa de: se, caso não tiver sido cadastrado na tabela de relacionamento, "faça" o cadastro é "retorne" ao procedimento de "inclusão" dos registros.

Atc.

Citação:
Mas imagine que eu estou a cadatrar o Cliente A.
Introduzo os seus dados e ele tem CodPostal AAAA e Localidade BBBB.
Se este registo de CodPostal não estiver já inserido na tabela CodPostal, vou ter um erro, por causa da chave estrangeira.
Eu penso que devo fazer uma procedure para inserir Cliente e, quando preencher o IdCodPostal no Cliente tenho de ir confirmar à tabela CodPostal se esse IdCodPostal já está inserido ou não.
Se já estiver não há problema.
O problema é se o IdCodPostal AAAA não está na tabela CodPostal.
Devo criar um trigger para quando inserir um IdCodPostal, que não esteja na Tabela CodPostal, ele chame a procedure de inserir CodPostal, com IdCospPostal e Localidade?
Acho que está um pouco confuso não?

Maria Araújo
   - 12 mai 2014

Mas então tenho de povoar a tabela CodPostal antes de inserir um Cliente?
Eu queria que ao cadastrar um Cliente, pudesse cadastrar também o CodPostal e Localidade em simultâneo.

Jair A.n.
   - 12 mai 2014

Não, conforme eu disse, ou faz o processo em separado, ou vai ter que criar a situação de pesquisa e gravação evitando a tentativa de inserir um registro que não tenha a informação relacionada na sua tabela CodPostal, regra geral.
para isso deverá criar uma procedure de insersão com as cláusulas de SE não encontrar, SE já estiver cadastrado etc...
Atc.

Citação:
Mas então tenho de povoar a tabela CodPostal antes de inserir um Cliente?
Eu queria que ao cadastrar um Cliente, pudesse cadastrar também o CodPostal e Localidade em simultâneo.

Marisiana
   - 12 mai 2014

Você pode fazer tudo isso em um único procedimento...
Este procedimento vai receber as informações a serem incluidas nas duas tabelas. A lógica seria +ou- a seguinte:

1º ) Faz um select para verificar se o código postal existe na tabela CODPOSTAL e retorna o valor em uma variavel
2º ) Cria uma condição para verificar se retornou valor na variável:
* Se a variável estiver vazia, você terá que cadastrar o código postal e, em seguida, se incluiu com sucesso, você inclui o cliente.
* Se retornou valor é porque o código postal já existe na tabela, então você só precisa incluir o cliente.

Utiliza os tratamentos de exceções corretamente que não tem como errar.

Maria Araújo
   - 14 mai 2014

Marisiana, segui o seu conselho e fiz:

CREATE PROCEDURE spInsertClient
@Nome VARCHAR(50),
@IdCodPostal CHAR(8),
@Localidade VARCHAR(20),
@Email VARCHAR(40)
AS
BEGIN
BEGIN TRY
BEGIN TRAN
DECLARE @Res CHAR(8)
SELECT IdCodPostal INTO Res FROM CodPostal WHERE IdCodPostal = @IdCodPostal

IF @Res IS NULL
BEGIN
INSERT INTO CodPostal(IdCodPostal, Localidade) VALUES(@IdCodPostal, @Localidade)
SET @Res = @IdCodPostal;

INSERT INTO Cliente(Nome, IdCodPostal, Email) VALUES(@Nome, @Res, @Email)
END

ELSE
BEGIN
INSERT INTO Cliente(Nome, IdCodPostal, Email) VALUES(@Nome, @IdCodPostal, @Email)
END

SELECT @@IDENTITY AS Retorno

COMMIT TRAN
END TRY

BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_MESSAGE() AS Retorno;
END CATCH
END

Se inserir um cliente com um Codigo Postal que não esteja na tabela CodPostal funciona tudo bem.
Mas quando executo a procedure pela 2ª vez, como dados diferentes, obtenho como retorno "There is already an object named 'Res' in the database"

Faabiianooc
   - 14 mai 2014

Acima dessa linha

#Código

SELECT IdCodPostal INTO Res FROM CodPostal WHERE IdCodPostal = @IdCodPostal


Coloque essa

#Código
if object_id('res','U') is not null
drop table res;


Isso faz com que seja verificado se a tabela que está sendo criada exista, caso existir sera dropada.

Maria Araújo
   - 15 mai 2014

Funciona perfeitamente.
O problema agora é se insiro um Cliente cujo IdCodPostal já está registado na tabela CodPostal, é o ELSE.
Dá um aviso de que estou inserindo chaves duplicadas.

Faabiianooc
   - 15 mai 2014

CREATE PROCEDURE spInsertClient
@Nome VARCHAR(50),
@IdCodPostal CHAR(8),
@Localidade VARCHAR(20),
@Email VARCHAR(40)
AS
BEGIN
BEGIN TRY
BEGIN TRAN
DECLARE @Res CHAR(8)

if object_id('Res','U') is not null
drop table Res;

SELECT IdCodPostal INTO Res FROM CodPostal WHERE IdCodPostal = @IdCodPostal

SET @Res = (select count(*) from Res); --Verifico se possui registros na tabela criada

IF @Res = 0
BEGIN
INSERT INTO CodPostal(IdCodPostal, Localidade) VALUES(@IdCodPostal, @Localidade)

INSERT INTO Cliente(Nome, IdCodPostal, Email) VALUES(@Nome, @Res, @Email)
END

ELSE
BEGIN
INSERT INTO Cliente(Nome, IdCodPostal, Email) VALUES(@Nome, @IdCodPostal, @Email)
END

SELECT @@IDENTITY AS Retorno

COMMIT TRAN
END TRY

BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_MESSAGE() AS Retorno;
END CATCH
END

Acho que funciona.

Maria Araújo
   - 15 mai 2014

Funciona sim.

Também dá se fizer SET @Res = (SELECT * FROM Res);

Quando criei a coluna Email na Tabela Cliente eu especifiquei que era UNIQUE KEY.

Mas se eu executar a procedure sempre com os mesmos dados estou inserido na Tabela Cliente somente linhas repetidas

Maria Araújo
   - 20 mai 2014

Culpa minha de inserir repetidos.
Estava mal especificada a UNIQUE KEY.