Jump to content


Photo

Como Relacionar Tabelas?


  • Faça o login para participar
18 replies to this topic

#1 bimonti

bimonti

    Super Veterano

  • Usuários
  • 2654 posts
  • Sexo:Masculino

Posted 10/02/2006, 08:46

EU li um tópico sobre relacionamento de tabelas, mas não consegui entender. Pelo que eu vi tenho que alterar o tipo da tabela e usar chaves estrangeiras.. Ótimo, posso procurar sobre o assunto na internet, mas antes gostaria de saber se é possível fazer isso, vai que eu leio um monte de texto e to no caminho errado...

Tenho 2 tabelas no MySQL:

Tb_empresas
-nome
-cod_empresa
-cod_categoria
-endereco

tb_categorias
-id
-cod_categoria
-titulo

Uso da seguinte forma, cadastro as categorias (Moda Masculina, Feminina, etc) e depois cadastro uma empresa e defino sua categoria (Moda Masculina é = a 3 por exemplo).

Meu problema é, todoas as lojas de roupas vendem roupas pra homem, mulher e criança ... <_<

E eu não sei como fazer pra falar que aquela empresa faz parte de 3 categorias ...
Pensei que talvez esse relacionamento ajudasse..

Se alguem tiver uma idéia de onde posso começar a informar eu agradeço muito mesmo... abraços
WebFórum - Equipe de Desenvolvimento - Monitor
Posted Image
Yeah I do have some stories, and it's true I want all the glory ...

#2 Thales Medeiros

Thales Medeiros

    24 Horas

  • Usuários
  • 426 posts
  • Sexo:Não informado
  • Localidade:Juiz de Fora/MG
  • Interesses:Programação em geral. Programo em PHP, ASP, PERL, VB, Delphi, C/C++, Java e com banco d dados&lt;br&gt;&lt;br&gt;Gosto tb d ajudar. Se precisar d mim, basta postar uma msg no Forum! Se eu souber, te responderei...

Posted 10/02/2006, 09:49

Oi, bimonti! Tudo bem?

Bom... Antes de lhe dar a solução para o seu problema, vou te explicar algumas coisas sobre relacionamento de tabelas.

Vc já deve ter ouvido falar que existem alguns tipos de relacionamentos, ditos "1 para muitos", "muitos para 1", "1 para 1" e "muitos para muitos". Se não ouviu falar, fique tranqüilo. Eu explico.

Imagine a seguinte situação: uma tabela para guardar várias empresas existentes e uma tabela para guardar todos os funcionários de todas as empresas. Cada uma possui dados específicos de cada objeto, ou seja, tabela de empresas guarda tudo de cada empresa (nome, endereço, CNPJ, etc, etc, etc), e tabela de funcionários guarda tudo, também (nome, endereço, telefone, CPF, etc).

Se quisermos relacionar estas duas tabelas, temos duas opções. Depende de que lado vamos enxergar os dados. Calma q vc vai entender...

Se observarmos a relação a partir da empresa, então vemos que cada empresa pode ter muitos funcionários. Vemos assim, a relação um para muitos (uma empresa ligada a muitos funcionários). Agora, se observarmos a relação a partir do funcionário, vemos que cada funcionário está ligado a uma e somente uma empresa. Ou seja, temos a relação um para um (um funcionário para uma empresa).

Agora entenda... Toda vez que tivermos uma relação um para um, ou muitos para um, então basta criar um campo na tabela de origem. Ou seja... Enxergue a relação funcionário - um para um - empresa. Como estamos observando pelo funcionário, então a gente fala de um campo na tabela funcionários. Bastaria, para resolver o problema de relações, acrescentar um campo na tabela funcionário para dizer a que empresa ele pertence.

Mas se observarmos pela empresa do meu exemplo e vermos que a relação é de um para muitos (uma empresa para muitos funcionários) ou, se em algum caso enxergarmos uma relação muitos para muitos (vou mostrar depois que este é o seu caso), então a gente precisa de uma tabela intermediária.

Para explicar este último parágrafo, vou entrar no seu exemplo pra vc ver, na prática, como funciona.

Em seu problema nós temos uma tabela de empresas e uma tabela de categorias. Se cada empresa pudesse estar em somente uma categoria (como vc chegou a citar), então a relação seria de 1 para 1 e bastaria criarmos na tabela empresas um campo pra dizer qual é a categoria a qual ela pertence. No entanto, uma empresa pode ter mais de uma categoria, então temos a relação de um para muitos.

Vamos começar a enxergar dos dois lados. Cada empresa pode ter diversas categorias (observando do lado da empresa), e cada categoria pode estar associada a diversas empresas (observando do lado da categoria). Desta forma, temos uma relação de muitos para muitos.

Vamos, desta forma, criar uma tabela intermediária para resolver nosso problema.

Teremos, no final das contas, uma tabela com os dados da empresa:
- nome
- cod_empresa
- endereco

Outra tabela com os dados das categorias:
- cod_categoria
- titulo

A tabela intermediária fará a relação muitos para muitos que necessitamos. Vou nomeá-la empresas_cats, mas pode colocar o nome q vc achar melhor. Seus campos:
- cod_empresa
- cod_categoria

Ambos estes campos serão chave, para que nunca exista duplicidade no cadastro de uma mesma empresa para uma mesma categoria. E, além disto, serão chaves estrangeiras.

No MySql, cria-se esta relação da seguinte forma:
CREATE TABLE empresas_cats (
    empresa_id int(3) not null,
    categoria_id int(3) not null,
    primary key(empresa_id, categoria_id),
    foreign key (empresa_id) references empresas(id),
    foreign key(categoria_id) references categorias(id)
);

Se vc quiser, pode também adicionar regras de eventos para cada chave estrangeira. Um evento é um DELETE ou um UPDATE, por exemplo. Repare: suponhamos que tenhamos a empresa de ID=4 e de nome "Empresa X". Suponhamos que na tabela empresas_cats, este ID esteja associado com as categorias de IDs 2 e 3. Então, existe isto:

SELECT id,nome FROM empresas WHERE empresa_id=4;
|---------------------|
|  id  |     nome     |
|---------------------|
|  4   | Empresa X |
|---------------------|

SELECT * FROM empresas_cats WHERE empresa_id=4;
|--------------------------------|
| empresa_id | categoria_id |
|--------------------------------|
|         4        |         2         |
|         4        |         3         |
|--------------------------------|

Se vc fizer um DELETE na tabela empresas e apagar a empresa de ID=4, na tabela empresas_cats ainda existirão aquelas referências vagas, certo? Estarão lá referenciando as categorias 2 e 3 com uma empresa que não existe.

Para corrigir isto, podemos, por exemplo, criar a chave estrangeira dizendo que, no evento apagar o registro na tabela pai (empresas), os registros filho associados na tabela filho (empresas_cats) sejam também apagados. Este processo chama-se apagar em cascata. Ou então, ao invés de apagar em cascata, podemos associar ao evento ON DELETE a ação de fazer com que os registros filhos fiquem nulos, ou algumas outras ações. Para fazer a ação apagar em cascata associada ao evento ON DELETE, devemos escrever isto na hora de criar a tabela:

CREATE TABLE empresas_cats (
    empresa_id int(3) not null,
    categoria_id int(3) not null,
    primary key(empresa_id, categoria_id),
    foreign key (empresa_id) references empresas(id) ON DELETE CASCADE,
    foreign key(categoria_id) references categorias(id) ON DELETE CASCADE
);

Vc pode fazer o mesmo para ações de UPDATE, também.

Para ver maiores informações, leia este endereço:

http://dev.mysql.com...onstraints.html

Espero ter ajudado em sua questão. Qualquer dúvida, basta perguntar!

Um abraço,
Thales Medeiros.
Sucesso é ganhar dinheiro fazendo o que você faria de graça.

#3 bimonti

bimonti

    Super Veterano

  • Usuários
  • 2654 posts
  • Sexo:Masculino

Posted 10/02/2006, 11:14

Cara, depois dessa aula só não aprende quem não quer.. Eu estou vendo o texto que você me falou e vou tentar aplicar aqui às minhas necessidades ....

Só uma questão, no outro tópico que eu li falava que era necessario criar a tabela para relacionar usando o tipo INNODB (acertei o nome ?), isso é necessário ?

-------------------------------------------------------------
Editado:

Que pergunta idiota, o nome do capitulo do MySQL é INNODB... :assobio:

Edição feita por: bimonti, 10/02/2006, 11:43.

WebFórum - Equipe de Desenvolvimento - Monitor
Posted Image
Yeah I do have some stories, and it's true I want all the glory ...

#4 Thales Medeiros

Thales Medeiros

    24 Horas

  • Usuários
  • 426 posts
  • Sexo:Não informado
  • Localidade:Juiz de Fora/MG
  • Interesses:Programação em geral. Programo em PHP, ASP, PERL, VB, Delphi, C/C++, Java e com banco d dados&lt;br&gt;&lt;br&gt;Gosto tb d ajudar. Se precisar d mim, basta postar uma msg no Forum! Se eu souber, te responderei...

Posted 10/02/2006, 12:42

hehehehehe.. Comédia!

Mas não é uma pergunta idiota. Só q cada tabela precisa, sim, ser do tipo INNODB.

Um grande abraço,
Thales Medeiros.
Sucesso é ganhar dinheiro fazendo o que você faria de graça.

#5 Peri

Peri

    Consultor SAP

  • Usuários
  • 565 posts
  • Sexo:Não informado
  • Localidade:São Paulo - SP

Posted 10/02/2006, 13:05

Dica de link sobre tipos de tabelas no mysql

http://phpbrasil.com...rint.php/id/397


[]s
+-----------------------------------------------------------------------------------------------------------
UH Terêrê ... Voltei!

#6 Rodrigo

Rodrigo

    oi!

  • Usuários
  • 995 posts
  • Sexo:Não informado
  • Interesses:Diretório de sites - http://www.acheinobrasil.com.br

Posted 10/02/2006, 13:58

ou vc pode simplesmente relacionar direto na consulta usando um innerjoin ou um alias... exemplo:

$sql="select e.nome,e.cod_empresa,e.endereco,c.titulo from tb_empresas e, tb_categorias c where e.cod_categoria=c.cod_categoria";

;)

#7 bimonti

bimonti

    Super Veterano

  • Usuários
  • 2654 posts
  • Sexo:Masculino

Posted 10/02/2006, 14:02

Maravilha garoto, to conseguindo fazer aqui, até a parte de fazer os SELECTs que eu to meio perdido. Veja como ficou minhas tabelas:

tb_anunciantes (cadastro das empresas):
- cod_empre (1)
- nome (Empresa A)
- endereco (Rua Pedra)

tb_categorias (armazena as categorias):
- cod_categoria (1)
- titulo (Moda Masculina)

tb_related (a intermediária):
- cod_empre (1)
- cod_cat (1)

Coloquei entre parenteses um exmplo de dado. Agora o problema é o seguinte, a página que exibe as empresas da categoria moda masculina se chama cat.php

Para exibir só moda masculina eu chama assim cat.php?cat=1

Antigamente meu SELECT era assim:
SELECT * FROM tb_anunciantes WHERE cod_categoria ='$cat'

Sendo que a variavel $cat é o http_get_vars depois de tratado.

Só que agora eu não sei como fazer o select mais, eu tenho que selecionar na tabela tb_related as empresas com categoria igual a $cat e depois como eu faço pra pegar as empresas ??

To viajando legal aqui, sem noção ...
Obrigado pela atenção ... (y)
WebFórum - Equipe de Desenvolvimento - Monitor
Posted Image
Yeah I do have some stories, and it's true I want all the glory ...

#8 Peri

Peri

    Consultor SAP

  • Usuários
  • 565 posts
  • Sexo:Não informado
  • Localidade:São Paulo - SP

Posted 10/02/2006, 15:40

Quando vc faz o relacionamento entre tabelas , o seu sql precisa necessariamente possuir este relacionamento , eh uma boa pratica que na sua clausula WHERE vc ja garanta o relacionamento e depois faca o resto da um look:

SELECT A.nome, A.endereco 
FROM tb_anunciantes as A, tb_categorias as B,tb_related as C 
WHERE A.cod_empre = C.cod_empre 
   AND  B.cod_categoria = C.cod_cat
   AND  B.cod_categoria ='$cat'



este "as " que vc esta vendo eh a atribuicao de um label para o nome da tabela , facilita o entendimento visual

eh isso manin
[]s
+-----------------------------------------------------------------------------------------------------------
UH Terêrê ... Voltei!

#9 bimonti

bimonti

    Super Veterano

  • Usuários
  • 2654 posts
  • Sexo:Masculino

Posted 11/02/2006, 09:43

Então, eu estava tentando fazer desso modo que você falou seguindo mais ou menos o que o rodrigo havia falado no tópico acima, mas no dele ele não especificou como vc falou usando o "as". Esse termo na verdade é o chamado "alias" ?

A estrutura da minha tabela está bem maior do que o que eu exemplifiquei aqui, então eu criei mais 2 tabelas simples para testar o comando e consegui usando o INNER JOIN e uma clausula WHERE para escolher os resultados, funcionou da forma que eu esperava, mas numa tabela pequena, na maior eu não sei se o reultado seria o esperado.

O que você acha melhor usar ? O INNER JOIN ou o relacionamento ??

Obrigado pelas respostas, todas me ajudaram muito...
Vlw :D
WebFórum - Equipe de Desenvolvimento - Monitor
Posted Image
Yeah I do have some stories, and it's true I want all the glory ...

#10 Thales Medeiros

Thales Medeiros

    24 Horas

  • Usuários
  • 426 posts
  • Sexo:Não informado
  • Localidade:Juiz de Fora/MG
  • Interesses:Programação em geral. Programo em PHP, ASP, PERL, VB, Delphi, C/C++, Java e com banco d dados&lt;br&gt;&lt;br&gt;Gosto tb d ajudar. Se precisar d mim, basta postar uma msg no Forum! Se eu souber, te responderei...

Posted 11/02/2006, 12:57

Oi, bimonti! Tudo bem?

Bom... Vamos a mais algumas definições pra vc entender como esta "coisa" funciona.

Quando vc cria um relacionamento explícito em uma tabela, utilizando inclusive chave estrangeira, isto é útil para se criar algo que chamamos de índices. Os índices são uma forma de se percorrer a tabela utilizando um campo específico, além daquele que é chave primária. Isto agiliza a consulta, de forma que quando criamos chaves estrangeiras indexadas, o relacionamento entre tabelas faz com que uma busca relacionada seja praticamente buscar em uma única tabela.

No entanto, para se fazer uma consulta relacionando tabelas, não precisa de forma alguma existir o relacionamento explícito. Veja o seu exemplo:

Uma tabela "empresas", uma tabela "categorias" e uma tabela "empresas_cats". Eu expliquei como vc criaria a tabela "empresas_cats" colocando uma chave estrangeira. Mas eu não disse como se criaria o índice. Portanto, lá vai:

CREATE TABLE empresas (
   empresa_id int(5) NOT NULL PRIMARY KEY,
   nome varchar(150) NOT NULL
) TYPE=INNODB;

CREATE TABLE categorias (
   categoria_id int(3) NOT NULL PRIMARY KEY,
   categoria varchar(50) NOT NULL
) TYPE=INNODB;

CREATE TABLE empresas_cats (
   empresa_id int(5) NOT NULL,
   categoria_id int(3) NOT NULL,
   PRIMARY KEY(empresa_id, categoria_id),
   INDEX(empresa_id, categoria_id),
   FOREIGN KEY(empresa_id) references empresas(empresa_id) ON DELETE CASCADE,
   FOREIGN KEY(categoria_id) references categorias(categoria_id) ON DELETE CASCADE
) TYPE=INNODB;

Bom... Desta forma, ainda temos a boa conveniência de que, quando deletarmos qualquer registro na tabela pai (empresas, por exemplo), todos os registros da tabela filho associados àquele também serão apagados. Mas o principal do relacionamento explícito não é isto. É que o banco de dados SABE realmente da existência da relação entre estas tabelas. Portanto, ele sabe que as tabelas "empresas" e "categorias" são as tabelas-pai da tabela "empresas_cats". Desta forma, o banco NÃO PERMITE que vc insira na tabela filho um registro com, por exemplo, um ID de uma empresa que não está cadastrada na tabela "empresas". Nem um registro com um ID de uma categoria que não está cadastrado na tabela "categorias". Isto que é um relacionamento definido!

Bem... Mas o que eu realmente gostaria de dizer é que não precisa existir chave estrangeira entre tabelas ou um relacionamento concretamente estruturado para que se consiga fazer referências. As buscas só não serão indexadas, mas isto nem será problema, também, pq os índices só começam a ajudar quando a tabela começa a ficar grande (para o MySql, começar a perder performance é uma tabela com mais de 5.000 registros, por exemplo).

Acho que agora vc entende que não é questão do que é melhor entre JOIN e relacionamento. Sempre tem que existir o JOIN. Tendo ou não relacionamento explícito entre tabelas, na hora de consultar, vc precisará usar o JOIN.

Entenda que JOIN não é só INNER JOIN. Existem LEFT JOIN, INNER JOIN e RIGHT JOIN. E que existem duas formas de se fazer JOIN: a que os bancos chamam de "the old JOIN style" e a que os bancos chamam de "new JOIN style". Ou seja, antigo estilo de JOIN e novo estilo de JOIN. No antigo, não usamos a palavra JOIN. Veja este exemplo de consulta que nos mostra todas as categorias (não o ID, mas o nome da categoria) de determinada empresa:

SELECT
    b.categoria
FROM
    empresas_cats AS a,
    categorias AS b
WHERE
    a.categoria_id=b.categoria_id AND
    a.empresa_id=3
ORDER BY b.categoria

Este é o velho estilo de JOIN. Vc coloca lá na cláusula WHERE qual é a relação entre a tabela "a" e a tabela "b". A propósito... Este AS é, sim, o tal "alias" de tabela. "Alias" é o ato de se dar um outro nome para uma tabela. Isto simplifica consultas pra não termos que ficar escrevendo o nome extenso da tabela pra dizer qual campo queremos buscar. Para esta consulta que fiz aí em cima, se eu não usasse "alias", veja como ficaria:

SELECT
    categorias.categoria
FROM
    empresas_cats,
    categorias
WHERE
    empresas_cats.categoria_id=categorias.categoria_id AND
    empresas_cats.empresa_id=3
ORDER BY b.categoria

Isto pq estou usando somente um JOIN e buscando somente um campo. Imagine se fossem 10 campos!! Muito melhor escrever "a.campo" do que "nome_da_tabela.campo", certo?

Bom... Para o novo estilo de JOIN, a consulta acima ficaria deste jeito:

SELECT
    b.categoria
FROM
    empresas_cats AS a LEFT JOIN categorias AS b ON (a.categoria_id=b.categoria_id)
WHERE a.empresa_id=3
ORDER BY b.categoria;

Bom... Vc citou um tal INNER JOIN, e eu usei um tal LEFT JOIN. Existem diferenças, ok? Mas neste caso os dois funcionariam, embora o mais "correto" (qdo vc ver o conceito dos dois, verá isto) para este caso seria o LEFT JOIN.

Eu poderia explicar todos os tipos de JOIN, masssss.... Como este POST já ficou grande demais, vou deixar isto para as cenas do próximo capítulo. Se tiver qualquer dúvida, já sabe que é só perguntar!

Espero ter esclarecido um pouquinho mais...

Um abraço,
Thales Medeiros.
Sucesso é ganhar dinheiro fazendo o que você faria de graça.

#11 bimonti

bimonti

    Super Veterano

  • Usuários
  • 2654 posts
  • Sexo:Masculino

Posted 11/02/2006, 15:05

Eu dei uma passada no W3Schools e colei todos os tópicos de SQL no Word e imprimi.. to com uma apostila improvisada aqui... heheh

Pelo que eu li:
- LEFT JOIN: retorna todas as linhas da primeira tabela
- RIGHT JOIN: retorna todas as linhas da segunda tabela
- INNER JOIN: retorna todas as linhas de ambas

Claro que há particularidades em cada uma delas, mas acho que agora já consegui entender um pouco mais sobre o SQL (joins, aliases, relacionamentos, etc).

Só uma outra coisa que eu estive pensando, no meu caso a tabela já existente é do tipo MyISAM, e pelo PHPMyAdmin eu consegui alterar para INNODB. A dúvida seria, para fazer a tabela intermediária pelo GUI do MyAdmin seria criar a tabela normalmente como INNODB, e depois ? Como eu defino que tal campo é chave estrangeira ?? Eu já vi que depois da tabela criada é possível vc criar os eventos (ON DELETE, etc) usando a opção Relation View.

Já que eu estou torrando a paciência de vocês só mais uma coisa. QUando eu crio um campo VARCHAR e não defino a campo Collation ele automaticamente define ele como latin1_swedish_ci. Tem algum problema ??
WebFórum - Equipe de Desenvolvimento - Monitor
Posted Image
Yeah I do have some stories, and it's true I want all the glory ...

#12 Felipe Pena

Felipe Pena

    O temor do Senhor é o princípio da sabedoria

  • Ex-Admins
  • 6441 posts
  • Sexo:Masculino

Posted 11/02/2006, 15:44

Eu acho legal utilizar um front-end, sem ser o phpMyAdmin, por exemplo: mysqlfront.
Assim você cria as tabelas com as definições dos campos, com isso você pega o SQL gerado e cria as tabelas no phpMyAdmin.
Mas não sei se existe a versão do mysqlfront com ajuda na definição de relacionamentos, integridade relacional, etc.

Já que eu estou torrando a paciência de vocês só mais uma coisa. QUando eu crio um campo VARCHAR e não defino a campo Collation ele automaticamente define ele como latin1_swedish_ci. Tem algum problema ??


Já vi reclamações desse tipo de Collatiom, alegando problemas em acentuação. Aqui eu utilizo apenas latin1.
Felipe Pena
[...] ó terra, terra, terra; ouve a palavra do Senhor. — Jeremias 22:29

#13 bimonti

bimonti

    Super Veterano

  • Usuários
  • 2654 posts
  • Sexo:Masculino

Posted 12/02/2006, 16:05

Estou só postando pra agradecer a todos que me ajudaram, consegui fazer o relacionamento da forma que eu esperava, apliquei os eventos na tabela pai e fucionou também, ela funciona no ON DELETE e ON UPDATE juntos, eu até descobri que uma tabela pode estar relacionada a mais de uma tabela.. heheh

Muito obrigado.
WebFórum - Equipe de Desenvolvimento - Monitor
Posted Image
Yeah I do have some stories, and it's true I want all the glory ...

#14 HaroNism

HaroNism

    Super Veterano

  • Usuários
  • 15385 posts
  • Sexo:Masculino
  • Localidade:San Miguel de Tucuman

Posted 25/09/2017, 11:29

Buying Secure Fedex Shipping Provera Tablet In Germany Viagra Dove Acquistare Viagra 100mg Without A Prescription cialis Canadian Cialis Reviews
Levitra Listino Farmacia Canadian Pharmancy cialis buy online Cialisis Barato Viagra Es Adictivo

#15 HaroNism

HaroNism

    Super Veterano

  • Usuários
  • 15385 posts
  • Sexo:Masculino
  • Localidade:San Miguel de Tucuman

Posted 07/10/2017, 18:50

Viagra Vrai Acheter Sisw Effects Cephalexin Dogs Over The Counter Fertility Drugs cialis Kamagra Donne




2 user(s) are reading this topic

0 membro(s), 2 visitante(s) e 0 membros anônimo(s)

IPB Skin By Virteq