sql >> Databáze >  >> RDS >> Mysql

MySQL:spojte mnoho tabulek do jednoho příkazu

Jak získat všechny potomky z uzlu stromu pomocí rekurzivního dotazu v MySql?

Je to opravdu problém pro MySql a je to klíčový bod této otázky, ale stále máte několik možností.

Předpokládejme, že máte taková ukázková data, ne tolik jako váš vzorek, ale dost na to, abyste je mohli demonstrovat:

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);

První volba:kód úrovně

Stejně jako ukázková data sloupce názvu v tabulce treeNode. (Nevím, jak se to řekne anglicky, okomentujte mě ohledně správného výrazu level code .)

Chcete-li získat všechny potomky C1 nebo G1 může to být jednoduché takto:

select * from treeNode where type = 'CATEGORY' and name like 'C1%' ;
select * from treeNode where type = 'GROUP' and name like 'G1%' ;

Tento přístup velmi preferuji, dokonce potřebuji, abychom tento kód vygenerovali před uložením treeNode do aplikace. Bude to efektivnější než rekurzivní dotaz nebo procedura, když máme velké množství záznamů. Myslím, že je to dobrý denormalizační přístup.

S tímto přístupem výrok chcete se připojit může být:

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

Milé, že?

Druhá volba:číslo úrovně

Připojte sloupec úrovně k tabulce treeNode, jak je znázorněno v DDL.

Údržba čísla úrovně je mnohem jednodušší než kód úrovně v aplikaci.

S číslem úrovně pro získání všech potomků C1 nebo G1 potřebujete malý trik, jako je tento:

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) ;

Tento přístup je pomalejší než první, ale stále rychlejší než rekurzivní dotaz.

Úplné sql na otázku bylo vynecháno. Stačí pouze nahradit tyto dva dílčí dotazy C a G dvěma výše uvedenými dotazy.

Poznámka:

Existuje mnoho podobných přístupů, jako je zde , zde nebo dokonce zde . Nebudou fungovat, pokud nebudou objednány podle čísla úrovně nebo kódu úrovně. Poslední dotaz můžete otestovat v tomto SqlFiddle změnou order by level order by id abyste viděli rozdíly.

Další možnost:Model vnořené sady

Podívejte se prosím na tento blog , ještě jsem netestoval. Ale myslím, že je to podobné jako u posledních dvou možností.

Je potřeba, abyste do tabulky uzlů stromu přidali levé a pravé číslo, abyste mezi ně uzavřeli ID všech potomků.



  1. Jak získat ID řádku v mysql

  2. Jak v MySQL zkopírovat obsah jedné tabulky do jiné tabulky ve stejné databázi?

  3. Chyba dotazu Python/MySQL:`Neznámý sloupec`

  4. Jak zvládnout fragmentaci sloupce auto_increment ID v MySQL