Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Twórz dynamiczne menu za pomocą zestawów zagnieżdżonych

Następujące zapytanie pozwoli Ci otworzyć dowolną ścieżkę (lub zestawy ścieżek) przy użyciu klauzuli have SQL i group_concat funkcja.

Poniżej znajduje się definicja tabeli i przykładowe dane, których użyłem:

drop table nested_set;

CREATE TABLE nested_set (
 id INT,
 name VARCHAR(20) NOT NULL,
 lft INT NOT NULL,
 rgt INT NOT NULL
);

INSERT INTO nested_set (id, name, lft, rgt) VALUES (1,'HEAD',1,28);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (2,'A',2,3);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (3,'B',4,17);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (4,'B1',5,10);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (5,'B1.1',6,7);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (6,'B1.2',8,9);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (7,'B2',11,16);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (8,'B2.1',12,13);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (9,'B2.2',14,15);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (10,'C',18,25);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (11,'C1',19,20);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (12,'C2',21,22);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (13,'C3',23,24);
INSERT INTO nested_set (id, name, lft, rgt) VALUES (14,'D',26,27);

Poniższe zapytanie daje całe drzewo (z wyjątkiem HEAD):

SELECT
  node.id
, node.lft
, node.rgt
, node.name
,  GROUP_CONCAT(parent.name ORDER BY parent.lft  SEPARATOR "/" ) AS path
,  (COUNT(parent.lft) - 1) AS depth
FROM nested_set AS node
inner join nested_set AS parent
on node.lft BETWEEN parent.lft AND parent.rgt
where parent.lft > 1
GROUP BY node.id

Z wynikiem następujących po uruchomieniu na przykładowych danych:

+------+-----+-----+------+-----------+-------+
| id   | lft | rgt | name | path      | depth |
+------+-----+-----+------+-----------+-------+
|    2 |   2 |   3 | A    | A         |     0 |
|    3 |   4 |  17 | B    | B         |     0 |
|    4 |   5 |  10 | B1   | B/B1      |     1 |
|    5 |   6 |   7 | B1.1 | B/B1/B1.1 |     2 |
|    6 |   8 |   9 | B1.2 | B/B1/B1.2 |     2 |
|    7 |  11 |  16 | B2   | B/B2      |     1 |
|    8 |  12 |  13 | B2.1 | B/B2/B2.1 |     2 |
|    9 |  14 |  15 | B2.2 | B/B2/B2.2 |     2 |
|   10 |  18 |  25 | C    | C         |     0 |
|   11 |  19 |  20 | C1   | C/C1      |     1 |
|   12 |  21 |  22 | C2   | C/C2      |     1 |
|   13 |  23 |  24 | C3   | C/C3      |     1 |
|   14 |  26 |  27 | D    | D         |     0 |
+------+-----+-----+------+-----------+-------+

Następujące dodatki do powyższego zapytania zapewniają kontrolę potrzebną do otwierania różnych sekcji:

having
depth = 0
or ('<PATH_TO_OPEN>' =  left(path, length('<PATH_TO_OPEN>'))
   and depth = length('<PATH_TO_OPEN>') - length(replace('<PATH_TO_OPEN>', '/', '')) + 1)

Klauzula having stosuje filtry do wyników grupy według zapytania. Część "głębokość =0" ma na celu zapewnienie, że zawsze mamy podstawowe węzły menu (A, B, C i D). Następna część to część, która kontroluje, które węzły są otwarte. Porównuje ścieżkę węzłów z ustawioną ścieżką, którą chcesz otworzyć (''), aby sprawdzić, czy pasuje, a także upewnia się, że otwiera się tylko na poziomie ścieżki. Całość lub sekcję z logiką „” można powielać i dodawać w razie potrzeby, aby w razie potrzeby otworzyć wiele ścieżek. Upewnij się, że „” nie kończy się ukośnikiem (/).

Poniżej znajduje się kilka przykładów wyników, które pokazują, jak konstruować zapytania, aby uzyskać pożądane wyniki:

=========Open B==========

SELECT
  node.id
, node.lft
, node.rgt
, node.name
,  GROUP_CONCAT(parent.name ORDER BY parent.lft  SEPARATOR "/" ) AS path
,  (COUNT(parent.lft) - 1) AS depth
FROM nested_set AS node
inner join nested_set AS parent
on node.lft BETWEEN parent.lft AND parent.rgt
where parent.lft > 1
GROUP BY node.id
having
depth = 0
or ('B' =  left(path, length('B'))
   and depth = length('B') - length(replace('B', '/', '')) + 1)

+------+-----+-----+------+------+-------+
| id   | lft | rgt | name | path | depth |
+------+-----+-----+------+------+-------+
|    2 |   2 |   3 | A    | A    |     0 |
|    3 |   4 |  17 | B    | B    |     0 |
|    4 |   5 |  10 | B1   | B/B1 |     1 |
|    7 |  11 |  16 | B2   | B/B2 |     1 |
|   10 |  18 |  25 | C    | C    |     0 |
|   14 |  26 |  27 | D    | D    |     0 |
+------+-----+-----+------+------+-------+

=========Open B and B/B1==========

SELECT
  node.id
, node.lft
, node.rgt
, node.name
,  GROUP_CONCAT(parent.name ORDER BY parent.lft  SEPARATOR "/" ) AS path
,  (COUNT(parent.lft) - 1) AS depth
FROM nested_set AS node
inner join nested_set AS parent
on node.lft BETWEEN parent.lft AND parent.rgt
where parent.lft > 1
GROUP BY node.id
having
depth = 0
or ('B' =  left(path, length('B'))
   and depth = length('B') - length(replace('B', '/', '')) + 1)
or ('B/B1' =  left(path, length('B/B1'))
   and depth = length('B/B1') - length(replace('B/B1', '/', '')) + 1)

+------+-----+-----+------+-----------+-------+
| id   | lft | rgt | name | path      | depth |
+------+-----+-----+------+-----------+-------+
|    2 |   2 |   3 | A    | A         |     0 |
|    3 |   4 |  17 | B    | B         |     0 |
|    4 |   5 |  10 | B1   | B/B1      |     1 |
|    5 |   6 |   7 | B1.1 | B/B1/B1.1 |     2 |
|    6 |   8 |   9 | B1.2 | B/B1/B1.2 |     2 |
|    7 |  11 |  16 | B2   | B/B2      |     1 |
|   10 |  18 |  25 | C    | C         |     0 |
|   14 |  26 |  27 | D    | D         |     0 |
+------+-----+-----+------+-----------+-------+

=========Open B and B/B1 and C==========

SELECT
  node.id
, node.lft
, node.rgt
, node.name
,  GROUP_CONCAT(parent.name ORDER BY parent.lft  SEPARATOR "/" ) AS path
,  (COUNT(parent.lft) - 1) AS depth
FROM nested_set AS node
inner join nested_set AS parent
on node.lft BETWEEN parent.lft AND parent.rgt
where parent.lft > 1
GROUP BY node.id
having
depth = 0
or ('B' =  left(path, length('B'))
   and depth = length('B') - length(replace('B', '/', '')) + 1)
or ('B/B1' =  left(path, length('B/B1'))
   and depth = length('B/B1') - length(replace('B/B1', '/', '')) + 1)
or ('C' =  left(path, length('C'))
   and depth = length('C') - length(replace('C', '/', '')) + 1)

+------+-----+-----+------+-----------+-------+
| id   | lft | rgt | name | path      | depth |
+------+-----+-----+------+-----------+-------+
|    2 |   2 |   3 | A    | A         |     0 |
|    3 |   4 |  17 | B    | B         |     0 |
|    4 |   5 |  10 | B1   | B/B1      |     1 |
|    5 |   6 |   7 | B1.1 | B/B1/B1.1 |     2 |
|    6 |   8 |   9 | B1.2 | B/B1/B1.2 |     2 |
|    7 |  11 |  16 | B2   | B/B2      |     1 |
|   10 |  18 |  25 | C    | C         |     0 |
|   11 |  19 |  20 | C1   | C/C1      |     1 |
|   12 |  21 |  22 | C2   | C/C2      |     1 |
|   13 |  23 |  24 | C3   | C/C3      |     1 |
|   14 |  26 |  27 | D    | D         |     0 |
+------+-----+-----+------+-----------+-------+

O to chodzi. po prostu powtarzasz tę lub sekcję dla każdej ścieżki, którą musisz otworzyć.

Zobacz http://mikehillyer.com/articles/managing-hierarchical-data -w-mysql/ jeśli potrzebujesz ogólnych informacji o pracy z zestawami zagnieżdżonymi w MySQL.

Daj mi znać, jeśli masz jakieś pytania.

HTH,

-Dipin



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak chronić moje forum przed spamem?

  2. Konwertuj datę na format daty MYSQL

  3. Uzyskaj ostatni odrębny zestaw rekordów

  4. Ciąg znaków z indeksu z programistą SQL

  5. Dlaczego zapytania wykonywane z mysql workbench trwają znacznie dłużej niż wykonywanie ich bezpośrednio z mysql cli?