Znajdź najwyższy poziom pola hierarchicznego: z vs bez CTE

58

Uwaga: pytanie to zostało zaktualizowane, aby odzwierciedlić fakt, że obecnie używamy MySQL. Po zrobieniu tego chciałbym zobaczyć, o ile łatwiej byłoby, gdybyśmy przeszli na bazę danych obsługującą CTE.

Mam tabelę z odnośnikami do siebie z kluczem podstawowym idi kluczem obcym parent_id.

+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment | 
| parent_id  | int(11)      | YES  |     | NULL    |                | 
| name       | varchar(255) | YES  |     | NULL    |                | 
| notes      | text         | YES  |     | NULL    |                | 
+------------+--------------+------+-----+---------+----------------+

Biorąc pod uwagę name, w jaki sposób mogę wysłać zapytanie do rodzica najwyższego poziomu?

Biorąc pod uwagę name, w jaki sposób mogę zapytać wszystkie idzwiązane z rekordem name = 'foo'?

kontekst: Nie jestem dba, ale planuję poprosić dba o implementację tego typu struktury hierarchicznej i chciałbym przetestować niektóre zapytania. Motywację do tego opisali Kattge i in . 2011 .


Oto przykład relacji między identyfikatorami w tabeli:

wprowadź opis zdjęcia tutaj

-- -----------------------------------------------------
-- Create a new database called 'testdb'
-- -----------------------------------------------------
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

CREATE SCHEMA IF NOT EXISTS `testdb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
USE `testdb` ;

-- -----------------------------------------------------
-- Table `testdb`.`observations`
-- -----------------------------------------------------
CREATE  TABLE IF NOT EXISTS `testdb`.`observations` (
  `id` INT NOT NULL ,
  `parent_id` INT NULL ,
  `name` VARCHAR(45) NULL ,
  PRIMARY KEY (`id`) )
ENGINE = InnoDB;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

-- -----------------------------------------------------
-- Add Example Data Set
-- -----------------------------------------------------


INSERT INTO observations VALUES (1,3), (2,5), (3,NULL), (4,10), 
   (5,NULL), (6,1), (7,5), (8,10), (9,10), (10,3);
David LeBauer
źródło
4
MySQL jest wyjątkiem od instrukcji „prawie wszystkie DBMS”. Nie obsługuje zapytań rekurencyjnych. Jedyną szansą, jaką masz, jest napisanie procedury składowanej, która powtarza się przez drzewo i pobiera informacje. Lub - jeśli liczba poziomów jest ograniczona - użyj odpowiedniej liczby samodzielnych połączeń
a_horse_w_na_name

Odpowiedzi:

63

Zdecydowanie musisz to zrobić za pomocą języka procedur przechowywanych MySQL

Oto funkcja GetParentIDByIDzapisana w celu pobrania identyfikatora nadrzędnego o podanym identyfikatorze do wyszukania

DELIMITER $$
DROP FUNCTION IF EXISTS `junk`.`GetParentIDByID` $$
CREATE FUNCTION `junk`.`GetParentIDByID` (GivenID INT) RETURNS INT
DETERMINISTIC
BEGIN
    DECLARE rv INT;

    SELECT IFNULL(parent_id,-1) INTO rv FROM
    (SELECT parent_id FROM pctable WHERE id = GivenID) A;
    RETURN rv;
END $$
DELIMITER ;

Oto funkcja przechowywana wywoływana GetAncestrydo pobierania listy ParentIDs, począwszy od pierwszej generacji, od całej hierarchii, której identyfikator zaczyna się od:

DELIMITER $$
DROP FUNCTION IF EXISTS `junk`.`GetAncestry` $$
CREATE FUNCTION `junk`.`GetAncestry` (GivenID INT) RETURNS VARCHAR(1024)
DETERMINISTIC
BEGIN
    DECLARE rv VARCHAR(1024);
    DECLARE cm CHAR(1);
    DECLARE ch INT;

    SET rv = '';
    SET cm = '';
    SET ch = GivenID;
    WHILE ch > 0 DO
        SELECT IFNULL(parent_id,-1) INTO ch FROM
        (SELECT parent_id FROM pctable WHERE id = ch) A;
        IF ch > 0 THEN
            SET rv = CONCAT(rv,cm,ch);
            SET cm = ',';
        END IF;
    END WHILE;
    RETURN rv;
END $$
DELIMITER ;

Oto coś do wygenerowania przykładowych danych:

USE junk
DROP TABLE IF EXISTS pctable;
CREATE TABLE pctable
(
    id INT NOT NULL AUTO_INCREMENT,
    parent_id INT,
    PRIMARY KEY (id)
) ENGINE=MyISAM;
INSERT INTO pctable (parent_id) VALUES (0);
INSERT INTO pctable (parent_id) SELECT parent_id+1 FROM pctable;
INSERT INTO pctable (parent_id) SELECT parent_id+2 FROM pctable;
INSERT INTO pctable (parent_id) SELECT parent_id+3 FROM pctable;
INSERT INTO pctable (parent_id) SELECT parent_id+4 FROM pctable;
INSERT INTO pctable (parent_id) SELECT parent_id+5 FROM pctable;
SELECT * FROM pctable;

Oto, co generuje:

mysql> USE junk
Database changed
mysql> DROP TABLE IF EXISTS pctable;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE pctable
    -> (
    ->     id INT NOT NULL AUTO_INCREMENT,
    ->     parent_id INT,
    ->     PRIMARY KEY (id)
    -> ) ENGINE=MyISAM;
Query OK, 0 rows affected (0.05 sec)

mysql> INSERT INTO pctable (parent_id) VALUES (0);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO pctable (parent_id) SELECT parent_id+1 FROM pctable;
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> INSERT INTO pctable (parent_id) SELECT parent_id+2 FROM pctable;
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> INSERT INTO pctable (parent_id) SELECT parent_id+3 FROM pctable;
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> INSERT INTO pctable (parent_id) SELECT parent_id+4 FROM pctable;
Query OK, 8 rows affected (0.01 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> INSERT INTO pctable (parent_id) SELECT parent_id+5 FROM pctable;
Query OK, 16 rows affected (0.00 sec)
Records: 16  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM pctable;
+----+-----------+
| id | parent_id |
+----+-----------+
|  1 |         0 |
|  2 |         1 |
|  3 |         2 |
|  4 |         3 |
|  5 |         3 |
|  6 |         4 |
|  7 |         5 |
|  8 |         6 |
|  9 |         4 |
| 10 |         5 |
| 11 |         6 |
| 12 |         7 |
| 13 |         7 |
| 14 |         8 |
| 15 |         9 |
| 16 |        10 |
| 17 |         5 |
| 18 |         6 |
| 19 |         7 |
| 20 |         8 |
| 21 |         8 |
| 22 |         9 |
| 23 |        10 |
| 24 |        11 |
| 25 |         9 |
| 26 |        10 |
| 27 |        11 |
| 28 |        12 |
| 29 |        12 |
| 30 |        13 |
| 31 |        14 |
| 32 |        15 |
+----+-----------+
32 rows in set (0.00 sec)

Oto, co funkcje generują dla każdej wartości:

mysql> SELECT id,GetParentIDByID(id),GetAncestry(id) FROM pctable;
+----+---------------------+-----------------+
| id | GetParentIDByID(id) | GetAncestry(id) |
+----+---------------------+-----------------+
|  1 |                   0 |                 |
|  2 |                   1 | 1               |
|  3 |                   2 | 2,1             |
|  4 |                   3 | 3,2,1           |
|  5 |                   3 | 3,2,1           |
|  6 |                   4 | 4,3,2,1         |
|  7 |                   5 | 5,3,2,1         |
|  8 |                   6 | 6,4,3,2,1       |
|  9 |                   4 | 4,3,2,1         |
| 10 |                   5 | 5,3,2,1         |
| 11 |                   6 | 6,4,3,2,1       |
| 12 |                   7 | 7,5,3,2,1       |
| 13 |                   7 | 7,5,3,2,1       |
| 14 |                   8 | 8,6,4,3,2,1     |
| 15 |                   9 | 9,4,3,2,1       |
| 16 |                  10 | 10,5,3,2,1      |
| 17 |                   5 | 5,3,2,1         |
| 18 |                   6 | 6,4,3,2,1       |
| 19 |                   7 | 7,5,3,2,1       |
| 20 |                   8 | 8,6,4,3,2,1     |
| 21 |                   8 | 8,6,4,3,2,1     |
| 22 |                   9 | 9,4,3,2,1       |
| 23 |                  10 | 10,5,3,2,1      |
| 24 |                  11 | 11,6,4,3,2,1    |
| 25 |                   9 | 9,4,3,2,1       |
| 26 |                  10 | 10,5,3,2,1      |
| 27 |                  11 | 11,6,4,3,2,1    |
| 28 |                  12 | 12,7,5,3,2,1    |
| 29 |                  12 | 12,7,5,3,2,1    |
| 30 |                  13 | 13,7,5,3,2,1    |
| 31 |                  14 | 14,8,6,4,3,2,1  |
| 32 |                  15 | 15,9,4,3,2,1    |
+----+---------------------+-----------------+
32 rows in set (0.02 sec)

MORAL OF THE STORY: Rekurencyjne odzyskiwanie danych musi być skryptowane w MySQL

AKTUALIZACJA 24.10.2011 17:17 EDT

Oto odwrotność GetAncestry. Nazywam to GetFamilyTree.

Oto algorytm:

  • Umieść podany identyfikator w kolejce
  • Pętla
    • Usuń z kolejki do front_id
    • Pobierz wszystkie identyfikatory do dzieci kolejki, których identyfikator nadrzędny = identyfikator przedni
    • Dołącz dzieci_kolejki do listy_walutów (rv)
    • Kolejkuj dzieci kolejki
    • Powtarzaj, aż kolejka i kolejka_dzieci będą jednocześnie puste

Uważam, że z moich klas struktur danych i algorytmów w College'u nazywa się to czymś w rodzaju przejścia na drzewo przedpremierowe / przedrostkowe.

Oto kod:

DELIMITER $$

DROP FUNCTION IF EXISTS `junk`.`GetFamilyTree` $$
CREATE FUNCTION `junk`.`GetFamilyTree` (GivenID INT) RETURNS varchar(1024) CHARSET latin1
DETERMINISTIC
BEGIN

    DECLARE rv,q,queue,queue_children VARCHAR(1024);
    DECLARE queue_length,front_id,pos INT;

    SET rv = '';
    SET queue = GivenID;
    SET queue_length = 1;

    WHILE queue_length > 0 DO
        SET front_id = FORMAT(queue,0);
        IF queue_length = 1 THEN
            SET queue = '';
        ELSE
            SET pos = LOCATE(',',queue) + 1;
            SET q = SUBSTR(queue,pos);
            SET queue = q;
        END IF;
        SET queue_length = queue_length - 1;

        SELECT IFNULL(qc,'') INTO queue_children
        FROM (SELECT GROUP_CONCAT(id) qc
        FROM pctable WHERE parent_id = front_id) A;

        IF LENGTH(queue_children) = 0 THEN
            IF LENGTH(queue) = 0 THEN
                SET queue_length = 0;
            END IF;
        ELSE
            IF LENGTH(rv) = 0 THEN
                SET rv = queue_children;
            ELSE
                SET rv = CONCAT(rv,',',queue_children);
            END IF;
            IF LENGTH(queue) = 0 THEN
                SET queue = queue_children;
            ELSE
                SET queue = CONCAT(queue,',',queue_children);
            END IF;
            SET queue_length = LENGTH(queue) - LENGTH(REPLACE(queue,',','')) + 1;
        END IF;
    END WHILE;

    RETURN rv;

END $$

Oto, co produkuje każdy rząd

mysql> SELECT id,parent_id,GetParentIDByID(id),GetAncestry(id),GetFamilyTree(id) FROM pctable;
+----+-----------+---------------------+-----------------+--------------------------------------------------------------------------------------+
| id | parent_id | GetParentIDByID(id) | GetAncestry(id) | GetFamilyTree(id)                                                                    |
+----+-----------+---------------------+-----------------+--------------------------------------------------------------------------------------+
|  1 |         0 |                   0 |                 | 2,3,4,5,6,9,7,10,17,8,11,18,15,22,25,12,13,19,16,23,26,14,20,21,24,27,32,28,29,30,31 |
|  2 |         1 |                   1 | 1               | 3,4,5,6,9,7,10,17,8,11,18,15,22,25,12,13,19,16,23,26,14,20,21,24,27,32,28,29,30,31   |
|  3 |         2 |                   2 | 2,1             | 4,5,6,9,7,10,17,8,11,18,15,22,25,12,13,19,16,23,26,14,20,21,24,27,32,28,29,30,31     |
|  4 |         3 |                   3 | 3,2,1           | 6,9,8,11,18,15,22,25,14,20,21,24,27,32,31                                            |
|  5 |         3 |                   3 | 3,2,1           | 7,10,17,12,13,19,16,23,26,28,29,30                                                   |
|  6 |         4 |                   4 | 4,3,2,1         | 8,11,18,14,20,21,24,27,31                                                            |
|  7 |         5 |                   5 | 5,3,2,1         | 12,13,19,28,29,30                                                                    |
|  8 |         6 |                   6 | 6,4,3,2,1       | 14,20,21,31                                                                          |
|  9 |         4 |                   4 | 4,3,2,1         | 15,22,25,32                                                                          |
| 10 |         5 |                   5 | 5,3,2,1         | 16,23,26                                                                             |
| 11 |         6 |                   6 | 6,4,3,2,1       | 24,27                                                                                |
| 12 |         7 |                   7 | 7,5,3,2,1       | 28,29                                                                                |
| 13 |         7 |                   7 | 7,5,3,2,1       | 30                                                                                   |
| 14 |         8 |                   8 | 8,6,4,3,2,1     | 31                                                                                   |
| 15 |         9 |                   9 | 9,4,3,2,1       | 32                                                                                   |
| 16 |        10 |                  10 | 10,5,3,2,1      |                                                                                      |
| 17 |         5 |                   5 | 5,3,2,1         |                                                                                      |
| 18 |         6 |                   6 | 6,4,3,2,1       |                                                                                      |
| 19 |         7 |                   7 | 7,5,3,2,1       |                                                                                      |
| 20 |         8 |                   8 | 8,6,4,3,2,1     |                                                                                      |
| 21 |         8 |                   8 | 8,6,4,3,2,1     |                                                                                      |
| 22 |         9 |                   9 | 9,4,3,2,1       |                                                                                      |
| 23 |        10 |                  10 | 10,5,3,2,1      |                                                                                      |
| 24 |        11 |                  11 | 11,6,4,3,2,1    |                                                                                      |
| 25 |         9 |                   9 | 9,4,3,2,1       |                                                                                      |
| 26 |        10 |                  10 | 10,5,3,2,1      |                                                                                      |
| 27 |        11 |                  11 | 11,6,4,3,2,1    |                                                                                      |
| 28 |        12 |                  12 | 12,7,5,3,2,1    |                                                                                      |
| 29 |        12 |                  12 | 12,7,5,3,2,1    |                                                                                      |
| 30 |        13 |                  13 | 13,7,5,3,2,1    |                                                                                      |
| 31 |        14 |                  14 | 14,8,6,4,3,2,1  |                                                                                      |
| 32 |        15 |                  15 | 15,9,4,3,2,1    |                                                                                      |
+----+-----------+---------------------+-----------------+--------------------------------------------------------------------------------------+
32 rows in set (0.04 sec)

Algorytm działa poprawnie pod warunkiem, że nie ma ścieżek cyklicznych. Jeśli istnieją jakieś ścieżki cykliczne, musisz dodać kolumnę „odwiedzone” do tabeli.

Po dodaniu odwiedzanej kolumny, oto algorytm blokujący cykliczne relacje:

  • Umieść podany identyfikator w kolejce
  • Oznacz wszystkich odwiedzonych za pomocą 0
  • Pętla
    • Usuń z kolejki do front_id
    • Pobierz wszystkie identyfikatory do dzieci_kolejki, których ID_domeny = ID_ frontowy i odwiedzone = 0
    • Zaznacz wszystkie pobrane dzieci z kolejki za pomocą odwiedzonych = 1
    • Dołącz dzieci_kolejki do listy_walutów (rv)
    • Kolejkuj dzieci kolejki
    • Powtarzaj, aż kolejka i kolejka_dzieci będą jednocześnie puste

AKTUALIZACJA 24.10.2011 17:37 EDT

Utworzyłem nową tabelę o nazwie obserwacje i zapełniłem twoje przykładowe dane. Zmieniłem procedury składowane, aby używać obserwacji zamiast pctable. Oto twój wynik:

mysql> CREATE TABLE observations LIKE pctable;
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT INTO observations VALUES (1,3), (2,5), (3,0), (4,10),(5,0),(6,1),(7,5),(8,10),(9,10),(10,3);
Query OK, 10 rows affected (0.00 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM observations;
+----+-----------+
| id | parent_id |
+----+-----------+
|  1 |         3 |
|  2 |         5 |
|  3 |         0 |
|  4 |        10 |
|  5 |         0 |
|  6 |         1 |
|  7 |         5 |
|  8 |        10 |
|  9 |        10 |
| 10 |         3 |
+----+-----------+
10 rows in set (0.00 sec)

mysql> SELECT id,parent_id,GetParentIDByID(id),GetAncestry(id),GetFamilyTree(id) FROM observations;
+----+-----------+---------------------+-----------------+-------------------+
| id | parent_id | GetParentIDByID(id) | GetAncestry(id) | GetFamilyTree(id) |
+----+-----------+---------------------+-----------------+-------------------+
|  1 |         3 |                   3 |                 | 6                 |
|  2 |         5 |                   5 | 5               |                   |
|  3 |         0 |                   0 |                 | 1,10,6,4,8,9      |
|  4 |        10 |                  10 | 10,3            |                   |
|  5 |         0 |                   0 |                 | 2,7               |
|  6 |         1 |                   1 | 1               |                   |
|  7 |         5 |                   5 | 5               |                   |
|  8 |        10 |                  10 | 10,3            |                   |
|  9 |        10 |                  10 | 10,3            |                   |
| 10 |         3 |                   3 | 3               | 4,8,9             |
+----+-----------+---------------------+-----------------+-------------------+
10 rows in set (0.01 sec)

AKTUALIZACJA 24.10.2011, 18:22 EDT

Zmieniłem kod GetAncestry. Tak WHILE ch > 1powinno byćWHILE ch > 0

mysql> SELECT id,parent_id,GetParentIDByID(id),GetAncestry(id),GetFamilyTree(id) FROM observations;
+----+-----------+---------------------+-----------------+-------------------+
| id | parent_id | GetParentIDByID(id) | GetAncestry(id) | GetFamilyTree(id) |
+----+-----------+---------------------+-----------------+-------------------+
|  1 |         3 |                   3 | 3               | 6                 |
|  2 |         5 |                   5 | 5               |                   |
|  3 |         0 |                   0 |                 | 1,10,6,4,8,9      |
|  4 |        10 |                  10 | 10,3            |                   |
|  5 |         0 |                   0 |                 | 2,7               |
|  6 |         1 |                   1 | 1,3             |                   |
|  7 |         5 |                   5 | 5               |                   |
|  8 |        10 |                  10 | 10,3            |                   |
|  9 |        10 |                  10 | 10,3            |                   |
| 10 |         3 |                   3 | 3               | 4,8,9             |
+----+-----------+---------------------+-----------------+-------------------+
10 rows in set (0.01 sec)

Spróbuj teraz !!!

RolandoMySQLDBA
źródło
Funkcja GetParentIDByID (id) działa dobrze w select, ale GetAncestry (id) nie odpowiada. WYBIERZ id, GetParentIDByID (id) OD użytkowników; działa dobrze WYBIERZ id, GetAncestry (id) OD użytkowników; nie odpowiada ... po prostu wyświetl ładowanie w phpmyadmin
Simerjit Parmar
@RolandoMySQLDBA GetFamilyTree działa dobrze! Ale w przypadku większego drzewa robi się cykliczny. Czy możesz zmodyfikować funkcję DB dla odwiedzanej części
Nadeshwaran 27.04.18
Czy ktoś zastosował ścieżkę cykliczną?
عثمان غني
na GetFamilyTree?
عثمان غني
28

Pobieranie wszystkich rodziców określonego węzła:

WITH RECURSIVE tree AS ( 
   SELECT id, 
          name, 
          parent_id,
          1 as level 
   FROM the_table
   WHERE name = 'foo'

   UNION ALL 

   SELECT p.id,
          p.name,
          p.parent_id, 
          t.level + 1
   FROM the_table p
     JOIN tree t ON t.parent_id = p.id
)
SELECT *
FROM tree

Aby uzyskać węzeł główny, możesz np. ORDER BY levelWziąć pierwszy wiersz

Pobieranie wszystkich elementów potomnych określonego węzła:

WITH RECURSIVE tree AS ( 
   SELECT id, 
          name, 
          parent_id,
          1 as level 
   FROM the_table
   WHERE name = 'foo'

   UNION ALL 

   SELECT p.id,
          p.name,
          p.parent_id, 
          t.level + 1
   FROM your_table p
     JOIN tree t ON t.id = p.parent_id
)
SELECT *
FROM tree

(zwróć uwagę na warunek zamiany dla złączenia w rekurencyjnej części instrukcji)

Według mojej wiedzy następujące DBMS obsługują rekurencyjne CTE:

  • FirebirdSQL 2.1 (tak naprawdę pierwszy OpenSource DBMS, który je zaimplementował)
  • PostgreSQL 8.4
  • DB2 (nie wiem, która dokładnie wersja)
  • Oracle (od 11.2)
  • SQL Server 2005 i nowsze wersje
  • Teradata
  • H2
  • Sybase (nie wiem, która dokładnie wersja)

Edytować

W oparciu o twoje przykładowe dane, poniższe pobrałyby wszystkie poddrzewa z tabeli, w tym pełną ścieżkę dla każdego węzła jako dodatkową kolumnę:

with recursive obs_tree as (
   select id, parent_id, '/'||cast(id as varchar) as tree
   from observations
   where parent_id is null

   union all 

   select t.id, t.parent_id, p.tree||'/'||cast(t.id as varchar)
   from observations t
      join obs_tree p on t.parent_id = p.id
)
select id, parent_id, tree
from obs_tree
order by tree

Wynik byłby następujący:

id | Parent_id | drzewo
---- + ----------- + ---------
  3 | | / 3
  1 | 3 | / 3/1
  6 | 1 | / 3/1/6
 10 | 3 | / 3/10
  4 | 10 | / 3/10/4
  8 | 10 | / 3/10/8
  9 | 10 | / 3/10/9
  5 | | / 5
  2 | 5 | / 5/2
  7 | 5 | / 5/7
koń bez imienia
źródło
Otrzymasz ode mnie +1, ponieważ twój kod jest o wiele bardziej przejrzysty, intuicyjny i zwięzły. Istnieje o wiele mniej obręczy do przeskoczenia. Szkoda, że ​​MySQL nie zapewnił bardziej eleganckich mechanizmów rekurencyjnego pobierania danych.
RolandoMySQLDBA
8
@RolandoMySQLDBA: z mojej perspektywy MySQL całkowicie nie nadąża za najnowocześniejszymi funkcjami SQL, takimi jak funkcje okienkowania, rekurencyjne wyrażenia tabel, funkcje tabel, indeksy oparte na funkcjach, ograniczenia sprawdzające, ograniczenia odroczalne - żeby wymienić tylko kilka.
a_horse_w_na_name
8

Funkcja GetFamilyTree w odpowiedzi Rolando nie działa, gdy podany identyfikator ma więcej niż 4 liczby całkowite, ponieważ funkcja FORMAT MySQL dodaje przecinki dla tysięcy separatorów. Zmodyfikowałem zapisaną funkcję GetFamilyTree do pracy z dużymi identyfikatorami całkowitymi, jak poniżej:

WHILE queue_length > 0 DO
    IF queue_length = 1 THEN
    SET front_id = queue;
        SET queue = '';
    ELSE
    SET front_id = SUBSTR(queue,1,LOCATE(',',queue)-1);
        SET pos = LOCATE(',',queue) + 1;
        SET q = SUBSTR(queue,pos);
        SET queue = q;
    END IF;

front_id zdefiniowany wewnątrz pętli if else.

Sivakumar Natarayan
źródło
Twoja edycja jest pomocna. jednak zajęło mi kilka sekund, aby dowiedzieć się, którą linię zmieniłeś. :-)
hriziya