Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

MySQL:junte muitas tabelas em uma declaração

Como obter todos os descendentes de um nó de árvore com consulta recursiva em MySql?


É realmente um problema para o MySql e é um ponto-chave para essa pergunta, mas você ainda tem algumas opções.

Supondo que você tenha esses dados de amostra, não tanto quanto sua amostra, mas o suficiente para demonstrar:
create table treeNode(
id int, parent_id  int,  name varchar(10), type varchar(10),level int);
insert into treeNode 
(id, parent_id, name, type, level) values 
( 1,  0,  'C1    ', 'CATEGORY', 1),
( 2,  1,  'C1.1  ', 'CATEGORY', 2),
( 3,  2,  'C1.1.1', 'CATEGORY', 3),
( 4,  1,  'C1.2  ', 'CATEGORY', 2),
( 5,  4,  'C1.2.1', 'CATEGORY', 3),
( 3,  8,  'G1.1.1',    'GROUP', 3),
( 4,  9,  'G1.2  ',    'GROUP', 2),
( 5,  4,  'G1.2.1',    'GROUP', 3),
( 8,  9,  'G1.1  ',    'GROUP', 2),
( 9,  0,  'G1    ',    'GROUP', 1);

Primeira escolha:código de nível


Como os dados de amostra da coluna name na tabela treeNode. (não sei dizer em inglês, comente-me sobre a expressão correta de level code .)

Para obter todos os descendentes de C1 ou G1 poderia ser simples assim:
select * from treeNode where type = 'CATEGORY' and name like 'C1%' ;
select * from treeNode where type = 'GROUP' and name like 'G1%' ;

Eu prefiro muito essa abordagem, até preciso que geremos esses códigos antes de treeNode salvar em application. Será mais eficiente do que a consulta ou procedimento recursivo quando tivermos um grande número de registros. Eu acho que esta é uma boa abordagem de desnormalização.

Com essa abordagem, a declaração você deseja com join poderia ser:
SELECT distinct p.* --if there is only one tree node for a product, distinct is not needed
FROM product p
JOIN product_type pt
     ON pt.id= p.parent_id -- to get product type of a product
JOIN linked_TreeNode LC
     ON LC.product_id= p.id -- to get tree_nodes related to a product
JOIN (select * from treeNode where type = 'CATEGORY' and name like 'C1%' ) C --may replace C1% to concat('$selected_cat_name','%')
     ON LC.treeNode_id = C.id
JOIN (select * from treeNode where type = 'GROUP' and name like 'G1%' ) G --may replace G1% to concat('$selected_group_name','%')
     ON LC.treeNode_id = G.id
WHERE pt.name = '$selected_type'  -- filter selected product type, assuming using product.name, if using product.parent_id, can save one join by pt like your original sql

Doce, não é?

Segunda escolha:número do nível


Anexe uma coluna de nível à tabela treeNode, conforme mostrado na DDL.

O número do nível é muito mais fácil de manter do que o código do nível em aplicação.

Com número de nível para obter todos os descendentes de C1 ou G1 precisa de um pequeno truque como este:
SELECT id, parent_id, name, type, @pv:=concat(@pv,',',id) as link_ids 
  FROM (select * from treeNode where type = 'CATEGORY' order by level) as t
  JOIN (select @pv:='1')tmp
 WHERE find_in_set(parent_id,@pv)
    OR find_in_set(id,@pv);
 -- get all descendants of `C1`

SELECT id, parent_id, name, type, @pv:=concat(@pv,',',id) as link_ids 
  FROM (select * from treeNode where type = 'GROUP' order by level) as t
  JOIN (select @pv:=',9,')tmp
 WHERE find_in_set(parent_id,@pv)
    OR find_in_set(id,@pv) ;

Essa abordagem é mais lenta que a primeira, mas ainda mais rápida que a consulta recursiva.

O sql completo para a pergunta omitido. Só precisa substituir essas duas subconsultas de C e G por duas consultas acima.

Observação:

Existem muitas abordagens semelhantes, como aqui , aqui , ou mesmo aqui . Eles não funcionarão a menos que sejam ordenados por número de nível ou código de nível. Você pode testar a última consulta neste SqlFiddle alterando order by level para order by id para ver as diferenças.

Outra opção:o modelo de conjunto aninhado


Consulte este blog , ainda não testei. Mas eu acho que é semelhante às duas últimas opções.

É necessário adicionar um número à esquerda e um número à direita à tabela de nós de árvore para incluir os IDs de todos os descendentes entre eles.