Mysql
 sql >> база данни >  >> RDS >> Mysql

MySQL:съединете много таблици в едно изявление

Как да получите всички наследници от дървовиден възел с рекурсивна заявка в MySql?

Това наистина е проблем за MySql и е ключова точка за този въпрос, но все пак имате някои възможности за избор.

Ако приемем, че имате такива примерни данни, не толкова много, колкото вашата извадка, но достатъчно, за да демонстрирате:

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

Първи избор:код на ниво

Като примерните данни на колоната с име в таблицата treeNode. (Не знам как да го кажа на английски, коментирайте ме за правилния израз на level code .)

За да получите всички наследници на C1 или G1 може да бъде просто като това:

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

Много предпочитам този подход, дори трябва да генерираме този код, преди treeNode да бъде запазен в приложението. Ще бъде по-ефективно от рекурсивната заявка или процедура, когато имаме голям брой записи. Мисля, че това е добър подход за денормализиране.

С този подходизявлението искате с присъединяване може да бъде:

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

Сладко, нали?

Втори избор:номер на ниво

Добавете колона на ниво към таблицата treeNode, както е показано в DDL.

Номерът на ниво се поддържа много по-лесно от кода на ниво в приложението.

С номер на ниво за получаване на всички наследници на C1 или G1 трябва малък трик като този:

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

Този подход е по-бавен от първия, но все пак по-бърз от рекурсивната заявка.

Пълният sql към въпроса е пропуснат. Трябва само да замените тези две подзаявки на C и G с две заявки по-горе.

Забележка:

Има много подобни подходи като тук , тук , или дори тук . Те няма да работят, освен ако не са подредени по номер на ниво или код на ниво. Можете да тествате последната заявка в този SqlFiddle чрез промяна на order by level за order by id за да видите разликите.

Друг избор:Моделът на вложен набор

Моля, вижте този блог , още не съм тествал. Но мисля, че е подобно на последните два варианта.

Трябва да добавите ляво число и дясно число към таблицата с дървовидни възли, за да обградите идентификаторите на всички наследници между тях.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Намерете несравними записи

  2. Нуждаете се от помощ за развъртане в mysql с множество колони за дата

  3. SQL заявката не показва очаквания резултат

  4. Настройка на отдалечена връзка с MySQL база данни

  5. Не може да се AES_DECRYPT след AES_ENCRYPT в mysql