Usuário com melhor resposta
Relacionamento entre tabelas

Pergunta
-
Pessoal estou com uma pequena dúvida e estou pedindo um help!!
Tenho que relacionar um campo de uma tabela com outro que não é chave primaria, como faço? Vou postar o código:
create table tbCliente
(
idCliente int primary key not null,
nome varchar(80) not null,
cpf char(14) not null,
telefone char(13),
endereco varchar(max),
bairro varchar(100),
cidade varchar(100),
estado varchar(100),
dataDia varchar(50),
cadastradoPor varchar(50)
)------------------------------------
create table tbOrdemServico
(
idOrdem int primary key not null,
idCliente int not null,
idServico int not null,
dataDia varchar(50),
cadastradorPor varchar(50),
/*Chave estrangeira idCliente*/
CONSTRAINT FK_tbOrdemServico_tbCliente_idCliente FOREIGN KEY(idCliente) REFERENCES tbCliente(idCliente),
/*Chave estrangeira idServico*/
CONSTRAINT FK_tbOrdemServico_tbServico_idServico FOREIGN KEY(idServico) REFERENCES tbServico(idServico)
)Queria saber se posso adicionar um campo nome na tabela de baixo usando os dados da promeira tabela, como o campo "idCliente" que usa o código da primeira tabela. Sei que o código é chave primaria na primeira e chave extrageira na segunda, eis aí o "X" da questão, como criar o campo nome na tabela de baixo usando os nomes da tabela de cima?
Pessoal desde já fico muito agradecido
JAVF
Respostas
-
Normalmente esse tipo de redundância é desnecessária, pois você resolve isso facilmente com um Join entre as tabelas. Porém, às vezes ela se faz necessária pela vantagem do ganho de desempenho para buscar a informação.
Ou seja, se você tem diversas consultas nas quais precisa buscar o nome do cliente e se um Join "custa" muito caro para o SQL, devido ao tamanho das tabelas, "pode ser" que seja mais vantajoso replicar a informação. Ainda que você tenha índices que possa te favorecer nestas tabelas, realmente existem casos onde a redundância de informações acaba sendo mais útil, devido à alguma estratégia.
Assim sendo, saiba que uma chave estrangeira pode ser criada não somente contra uma chave primária, mas também contra um índice único. O fato é que uma chave estrangeira só pode ser criada contra uma tabela que garanta que aquela coluna que fará parte da referência é única, isto é, não se repete.
Dessa forma, o código abaixo poderia ser utilizado:
create table tbCliente ( idCliente int primary key not null, nome varchar(80) not null, cpf char(14) not null, telefone char(13), endereco varchar(max), bairro varchar(100), cidade varchar(100), estado varchar(100), dataDia varchar(50), cadastradoPor varchar(50), Constraint UQ_Nome unique (nome) ) ------------------------------------ create table tbOrdemServico ( idOrdem int primary key not null, idCliente int not null, NomeCliente varchar(80) not null, idServico int not null, dataDia varchar(50), cadastradorPor varchar(50), /*Chave estrangeira idCliente*/ CONSTRAINT FK_tbOrdemServico_tbCliente_idCliente FOREIGN KEY(idCliente) REFERENCES tbCliente(idCliente), CONSTRAINT FK_tbOrdemServico_tbCliente_NmCliente FOREIGN KEY(NomeCliente) REFERENCES tbCliente(nome) )
Veja que é criado um índice único para o nome do cliente e, na tabela de ordem serviço, é criada uma foreign key contra a coluna nome.
Isto poderia ser utilizado, mas não deve: se você fizer isso não poderá mais ter clientes com mesmo nome. E sabemos que muitas pessoas possuem exatamente o mesmo nome. Então não dá pra criarmos uma regra na qual o nome tem que ser único.
Com isso, o único recurso que você tem em mãos é mudar a chave primária da tabela Clientes, para que seja composta tanto pelo Id quanto pelo nome. Porém, isso pode atrapalhar o resto da sua vida, pois em toda tabela que você precisar criar uma ligação com a tabela Clientes, terá que criar uma coluna nome em tal tabela e usar os dois campos (Id e nome) para fazer a referência. Ou seja, pode ser um tiro no pé.
Seria algo como isso:
create table tbCliente ( idCliente int not null, nome varchar(80) not null, cpf char(14) not null, telefone char(13), endereco varchar(max), bairro varchar(100), cidade varchar(100), estado varchar(100), dataDia varchar(50), cadastradoPor varchar(50), Constraint PK_Cliente Primary Key (idCliente,nome) ) ------------------------------------ create table tbOrdemServico ( idOrdem int primary key not null, idCliente int not null, NomeCliente varchar(80) not null, idServico int not null, dataDia varchar(50), cadastradorPor varchar(50), /*Chave estrangeira idCliente*/ CONSTRAINT FK_tbOrdemServico_tbCliente_idCliente FOREIGN KEY(idCliente,NomeCliente) REFERENCES tbCliente(idCliente,nome) )
Enfim, acho que não deve fazer isso, a menos que tenha um motivo muito sólido.
Acho que não deve nem ter o nome do cliente na tabela de ordem de serviço, mas se for realmente necessário e se quiser garantir a consistência das informações, talvez precise criar uma trigger para isso.
Roberson Ferreira - Database Developer
Acesse: www.robersonferreira.com.br
Email: contato@robersonferreira.com.brSe esta sugestão for útil, por favor, classifique-a como útil.
Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.- Marcado como Resposta Gustavo M. Guimarães segunda-feira, 10 de dezembro de 2012 12:17
Todas as Respostas
-
JAVF,
Para que exatamente vc precisa desse campo? Você já possui o IdCliente na tabela tbOrdemServico, dependendo do motivo você consegue resolver com a criação de uma view com um join entre essas duas tabelas. Nesse seu caso, você só iria gerar redundância de informações.
Abs,
-
Normalmente esse tipo de redundância é desnecessária, pois você resolve isso facilmente com um Join entre as tabelas. Porém, às vezes ela se faz necessária pela vantagem do ganho de desempenho para buscar a informação.
Ou seja, se você tem diversas consultas nas quais precisa buscar o nome do cliente e se um Join "custa" muito caro para o SQL, devido ao tamanho das tabelas, "pode ser" que seja mais vantajoso replicar a informação. Ainda que você tenha índices que possa te favorecer nestas tabelas, realmente existem casos onde a redundância de informações acaba sendo mais útil, devido à alguma estratégia.
Assim sendo, saiba que uma chave estrangeira pode ser criada não somente contra uma chave primária, mas também contra um índice único. O fato é que uma chave estrangeira só pode ser criada contra uma tabela que garanta que aquela coluna que fará parte da referência é única, isto é, não se repete.
Dessa forma, o código abaixo poderia ser utilizado:
create table tbCliente ( idCliente int primary key not null, nome varchar(80) not null, cpf char(14) not null, telefone char(13), endereco varchar(max), bairro varchar(100), cidade varchar(100), estado varchar(100), dataDia varchar(50), cadastradoPor varchar(50), Constraint UQ_Nome unique (nome) ) ------------------------------------ create table tbOrdemServico ( idOrdem int primary key not null, idCliente int not null, NomeCliente varchar(80) not null, idServico int not null, dataDia varchar(50), cadastradorPor varchar(50), /*Chave estrangeira idCliente*/ CONSTRAINT FK_tbOrdemServico_tbCliente_idCliente FOREIGN KEY(idCliente) REFERENCES tbCliente(idCliente), CONSTRAINT FK_tbOrdemServico_tbCliente_NmCliente FOREIGN KEY(NomeCliente) REFERENCES tbCliente(nome) )
Veja que é criado um índice único para o nome do cliente e, na tabela de ordem serviço, é criada uma foreign key contra a coluna nome.
Isto poderia ser utilizado, mas não deve: se você fizer isso não poderá mais ter clientes com mesmo nome. E sabemos que muitas pessoas possuem exatamente o mesmo nome. Então não dá pra criarmos uma regra na qual o nome tem que ser único.
Com isso, o único recurso que você tem em mãos é mudar a chave primária da tabela Clientes, para que seja composta tanto pelo Id quanto pelo nome. Porém, isso pode atrapalhar o resto da sua vida, pois em toda tabela que você precisar criar uma ligação com a tabela Clientes, terá que criar uma coluna nome em tal tabela e usar os dois campos (Id e nome) para fazer a referência. Ou seja, pode ser um tiro no pé.
Seria algo como isso:
create table tbCliente ( idCliente int not null, nome varchar(80) not null, cpf char(14) not null, telefone char(13), endereco varchar(max), bairro varchar(100), cidade varchar(100), estado varchar(100), dataDia varchar(50), cadastradoPor varchar(50), Constraint PK_Cliente Primary Key (idCliente,nome) ) ------------------------------------ create table tbOrdemServico ( idOrdem int primary key not null, idCliente int not null, NomeCliente varchar(80) not null, idServico int not null, dataDia varchar(50), cadastradorPor varchar(50), /*Chave estrangeira idCliente*/ CONSTRAINT FK_tbOrdemServico_tbCliente_idCliente FOREIGN KEY(idCliente,NomeCliente) REFERENCES tbCliente(idCliente,nome) )
Enfim, acho que não deve fazer isso, a menos que tenha um motivo muito sólido.
Acho que não deve nem ter o nome do cliente na tabela de ordem de serviço, mas se for realmente necessário e se quiser garantir a consistência das informações, talvez precise criar uma trigger para isso.
Roberson Ferreira - Database Developer
Acesse: www.robersonferreira.com.br
Email: contato@robersonferreira.com.brSe esta sugestão for útil, por favor, classifique-a como útil.
Se ela lhe ajudar a resolver o problema, por favor, marque-a como Resposta.- Marcado como Resposta Gustavo M. Guimarães segunda-feira, 10 de dezembro de 2012 12:17