Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Marcelo Garbin

Categoria com Subcategorias

Recommended Posts

Fiz algumas pesquisas e testes sobre "self join", porém ainda não consegui fazer o que eu gostaria, acredito que seja uma dúvida clássica isso já, porém não estou conseguindo resolver. Vou dar um exemplo.

 

Minha dúvida é ref. a Categorias e Subcategorias. A estrutura básica que tenho da tabela Categorias é a seguinte:

id_categoria

id_categoria_pai (referenciando essa mesma tabela, campo null)

nome

descricao

ativo

 

Certo?

Outra tabela é por exemplo, Produtos:

id_produto

id_categoria (fk_tbl_categorias, not null)

nome

descricao

ativo

 

Fiz esse exemplo simples, porém acredito que deve servir para vários outros exemplos que utilizam subcategorias (Se não for, me corrija).

 

Minha dúvida é, como posso fazer um SELECT entre essas duas tabelas, onde irei ter os campos: nome da categoria e nome também da subcategoria juntamente com o nome do produto e outras informações que eu achar pertinente. Como consigo fazer isso?

Lembrando que o produto pode ou não ter subcategoria, mas a categoria é obrigatório ter. Valeu...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tem bastante exemplo na net sobre JOIN.

 

Mas basicamente para fazer a ligação você precisa verificar se a tabela é do mesmo tipo primitivo.

 

INT 'deveria' ser INT, varchar deve ser varchar e assim por diante....

 

Vamos criar um banco aqui só de zoas como exemplo.

create database imasters;
use imasters;
CREATE TABLE profissao(
	 id INT (8) primary key auto_increment
	,nome VARCHAR(50)
)Engine=InnoDb;

INSERT INTO profissao (nome) VALUES ('Programador'), ('Jedi'), ('Gravatinha'), ('Dev PL/SQL'), ('DBA');





CREATE TABLE pessoa(
	 id INT (8) primary key auto_increment
	,nome VARCHAR(50)
	,profissao_id int(8) not null references profissao(id)
)Engine=InnoDb;


INSERT INTO pessoa(nome, profissao_id) VALUE ('Joao', 1); /* Programador */
INSERT INTO pessoa(nome, profissao_id) VALUE ('Anakin', 2); /* Jedi */
INSERT INTO pessoa(nome, profissao_id) VALUE ('Sergio', 3); /* Gravatinha */
INSERT INTO pessoa(nome, profissao_id) VALUE ('Yoda', 2); /* Jedi */

OK... agora temos um banco com 2 tabelas.

Se por exemplo listarmos todas as profissões rola esse result:

mysql> SELECT * FROM PROFISSAO;
+----+-------------+
| id | nome        |
+----+-------------+
|  1 | Programador |
|  2 | Jedi        |
|  3 | Gravatinha  |
|  4 | Dev PL/SQL  |
|  5 | DBA         |
+----+-------------+

Bacana... se listarmos todos as pessoas:

mysql> select * from pessoa;
+----+--------+--------------+
| id | nome   | profissao_id |
+----+--------+--------------+
|  1 | Joao   |            1 |
|  2 | Anakin |            2 |
|  3 | Sergio |            3 |
|  4 | Yoda   |            2 |
+----+--------+--------------+

Ai é que está o lance do relacionamento no caso queremos trazer o resultado do nome na profissao_id.

Vamos pegar o Yoda ... pq o Yoda é mestre HSAUHASUSA

/*Exemplo 1: */
SELECT
	 pessoa.id
	,pessoa.nome
	,profissao.nome as profissao_nome
FROM 
	pessoa
LEFT OUTER JOIN profissao ON(
	pessoa.profissao_id = profissao.id
)
WHERE pessoa.id = 4;
+----+------+----------------+
| id | nome | profissao_nome |
+----+------+----------------+
|  4 | Yoda | Jedi           |
+----+------+----------------+

...

LEFT OUTER JOIN profissao ON(

pessoa.profissao_id = profissao.id
)

 

Neste trecho ele liga todos os resultados com a tabela e assim podemos especificar ela no SELECT.

 

 

Banco de dados é viagem,

Outro exemplo só pra tentar deixar mais claro como ele funciona (ou embananar mais sua cabeça haha)

 

Podemos também trazer todos os resultados e 'refinar' dentro do Where (oq não deixa muito legível)

 

Ex:

/*Exemplo 2: */
SELECT
	 pessoa.id
	,pessoa.nome
	,profissao.nome as profissao_nome
FROM 
	pessoa, profissao
WHERE 
	pessoa.profissao_id = profissao.id
	AND pessoa.id = 4
; 

De qlq forma prefira sempre ao fazer Joins o exemplo 1.

Se tu curtir ir mais na parte teórica da parada vale a pena dar uma lida:

https://pt.wikipedia.org/wiki/Diagrama_de_Venn

 

No HackerRank tem uma porrada de exercicios pra quem ta começando SQL, vale a pena conferir tmb:

https://www.hackerrank.com/

Compartilhar este post


Link para o post
Compartilhar em outros sites

http://dba.stackexchange.com/questions/46127/recursive-self-joins

Hierarchical queries, as those recursive queries are known, are not supported for MySQL.

 

 

Se você utilizar o PHP, poderá iniciar a consulta pelo topo:

'[...] WHERE id_categoria_pai IS NULL;'

E, pelo PHP, continuar a busca através dos níveis:

$statementSub = $pdo->prepare('SELECT * FROM categorias WHERE id_categoria_pai = :id_categoria_pai;');
foreach($statement AS $row) {
   $statementSub->bindParam(':id_categoria_pai' , $row['id_categoria']);
   $statementSub->execute();

   /** mais códigos **/
}

Esse trecho de código, acima, irá ajudar a buscar a categoria filha. Após, é só criar a recursividade, e você poderá ter N níveis de categoria.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olha só, minhas tabelas são essas:

 

Screen_Hunter_15_May_20_10_44.png

 

Até aí acredito que a modelagem esteja ok, certo?

 

Aí no resultado eu gostaria de buscar os seguintes campos:

Screen_Hunter_15_May_20_10_47.png

 

Até consegui fazer essa busca, porém com resultados repetidos e onde é o categoria ele pega o nome da subcategoria caso o cadastro tenha uma, usei o seguinte código:

SELECT
	m.id_manual, m.titulo, m.arquivo, m.downloads, cat.id_categoria, cat.id_subcategoria, cat.categoria, cat.subcategoria
FROM
	nw_manuais_tecnicos m
LEFT JOIN
		(SELECT
			cp.id_categoria, cf.id_categoria_pai id_subcategoria,
			cp.nome categoria, cf.nome subcategoria
		FROM
			nw_manuais_tecnicos_categorias cp
		LEFT JOIN
			nw_manuais_tecnicos_categorias cf
		ON
			cp.id_categoria=cf.id_categoria_pai
		) cat
ON
	m.id_categoria=cat.id_categoria

Até estou fazendo a junção das duas tabelas, porém os campos não estão ficando certos, o que eu gostaria é que no campo categoria, ficasse o nome da categoria e caso tenha subcategoria o nome da subcategoria ficasse no campo subcategoria, consequentemente isso para os campos id_categoria e id_subcategoria.

 

Como eu poderia fazer isso? ou comente filtrando com PHP?

 

Gostaria de fazer somente uma Query pra isso se for possível.

Compartilhar este post


Link para o post
Compartilhar em outros sites

É mais confiável você utilizar uma consulta linear, que busque o topo da lista (ou base da árvore) e, utilizando o PHP, comece a iterar sobre os nodes. Pois somente com SQL (MySQL no caso) a quantidade de níveis ficará dependente do quanto você implementar com o SQL.

 

Outro ponto, você está montando a estrutura em árvore à partir do fim para o início, isso pode estar causando a duplicação. Sempre "comece do começo". Em uma estrutura em árvore, é a base.

 

Eu sugeriria montar a estrutura realizando as consultas e organizando os dados no PHP.

 

Pois somente com SQL, você possuirá uma estrutura em SQL muito engessada.

Compartilhar este post


Link para o post
Compartilhar em outros sites

É mais confiável você utilizar uma consulta linear, que busque o topo da lista (ou base da árvore) e, utilizando o PHP, comece a iterar sobre os nodes. Pois somente com SQL (MySQL no caso) a quantidade de níveis ficará dependente do quanto você implementar com o SQL.

 

Outro ponto, você está montando a estrutura em árvore à partir do fim para o início, isso pode estar causando a duplicação. Sempre "comece do começo". Em uma estrutura em árvore, é a base.

 

Eu sugeriria montar a estrutura realizando as consultas e organizando os dados no PHP.

 

Pois somente com SQL, você possuirá uma estrutura em SQL muito engessada.

 

Em termos de modelagem das tabelas, está correto ou teria algum ajuste?

Compartilhar este post


Link para o post
Compartilhar em outros sites

A modelagem está ok. A implementação que deve ser reformulada.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.