7
votes

Comment interroger une table MySQL pour afficher la racine et sa subchild.

SELECT UserID, UserName  FROM tbl_User WHERE ParentID=3 OR UserID=3 And TopID=1;

1 commentaires

MySQL ne prend pas en charge les requêtes hiérarchiques ou récursives. Si vous avez une profondeur maximale bien définie, vous pouvez utiliser ces nombreuses jointures.


4 Réponses :


2
votes

Eh bien, pas une mise en œuvre assez propre, mais que vous n'avez que les enfants et les sous-enfants, l'une de ces personnes pourrait fonctionner:

Query1: P>

SELECT UserID, UserName
FROM tbl_user 
WHERE UserID = 3
OR ParentID = 3
OR ParentID IN (SELECT UserID
    FROM tbl_user
    WHERE ParentID = 3);


2 commentaires

Je vois un bowvote, mais l'électeur n'explique pas pourquoi il a baissé. Hmm!


Je n'ai pas bownviote, et maintenant vous êtes au +2 mais votre exemple ne fonctionne pas s'il y a plus de 3 niveaux dans la hiérarchie. Si vous ajoutez un utilisateur qui est un enfant à l'utilisateur 5, il ne sera pas retourné dans votre exemple. Cela fonctionne pour la situation de l'OP fournie cependant.



5
votes

Il est techniquement possible de faire des requêtes hiérarchiques récursives dans MySQL à l'aide de procédures stockées.

Voici une adaptation à votre scénario: P>

CREATE TABLE `user` (
  `UserID` int(16) unsigned NOT NULL,
  `UserName` varchar(32),
  `ParentID` int(16) DEFAULT NULL,
  `TopID` int(16) DEFAULT NULL,
  PRIMARY KEY (`UserID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO user VALUES (1, 'abc', NULL, NULL), (2, 'edf', 1, 1), (3, 'gef', 1, 1), 
 (4, 'huj', 3, 1), (5, 'jdi', 4, 1), (6, 'das', 2, 1), (7, 'new', NULL, NULL), 
 (8, 'gka', 7, 7);

DELIMITER $$
DROP PROCEDURE IF EXISTS `Hierarchy` $$
CREATE PROCEDURE `Hierarchy` (IN GivenID INT, IN initial INT)
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE next_id INT;

    -- CURSOR TO LOOP THROUGH RESULTS --
    DECLARE cur1 CURSOR FOR SELECT UserID FROM user WHERE ParentID = GivenID;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    -- CREATE A TEMPORARY TABLE TO HOLD RESULTS --
    IF initial=1 THEN
        -- MAKE SURE TABLE DOESN'T CONTAIN OUTDATED INFO IF IT EXISTS (USUALLY ON ERROR) --
        DROP TABLE IF EXISTS OUT_TEMP; 
        CREATE TEMPORARY TABLE OUT_TEMP (userID int, UserName varchar(32));
    END IF;

    -- ADD OURSELF TO THE TEMPORARY TABLE --
    INSERT INTO OUT_TEMP SELECT UserID, UserName FROM user WHERE UserID = GivenID;

    -- AND LOOP THROUGH THE CURSOR --
    OPEN cur1;
    read_loop: LOOP
        FETCH cur1 INTO next_id;

        -- NO ROWS FOUND, LEAVE LOOP --
        IF done THEN
        LEAVE read_loop;
        END IF;

        -- NEXT ROUND --
        CALL Hierarchy(next_id, 0);     
    END LOOP;

    CLOSE cur1;

    -- THIS IS THE INITIAL CALL, LET'S GET THE RESULTS --
    IF initial=1 THEN
    SELECT * FROM OUT_TEMP;
        -- CLEAN UP AFTER OURSELVES --
        DROP TABLE OUT_TEMP; 
    END IF;
END $$
DELIMITER ;

CALL Hierarchy(3,1);
+--------+----------+
| userID | UserName |
+--------+----------+
|      3 | gef      |
|      4 | huj      |
|      5 | jdi      |
+--------+----------+
3 rows in set (0.07 sec)

Query OK, 0 rows affected (0.07 sec)

CALL Hierarchy(1,1);
+--------+----------+
| userID | UserName |
+--------+----------+
|      1 | abc      |
|      2 | edf      |
|      6 | das      |
|      3 | gef      |
|      4 | huj      |
|      5 | jdi      |
+--------+----------+
6 rows in set (0.10 sec)

Query OK, 0 rows affected (0.10 sec)


4 commentaires

J'ai copié votre procédure stockée et exécutée dans phpmyadmin et il a été exécuté, comment puis-je faire une requête pour voir le résultat dans ma phpmyadmin


Devrait être une requête SQL: hiérarchie d'appel ($ userid, 1);


Hiérarchie d'appel (2, 1); J'ai exécuté cela dans MySQL et il a lancé et Erreur # 1456 - La limite récursive 0 (définie par la variable max_sp_recursion_depth) a été dépassée pour la hiérarchie de routine,


Oui monsieur, comme mentionné mon premier point de puériculture, vous devrez augmenter cette variable. Pour les tests, vous pouvez la définir pour une session: Set Max_sp_recursion_depth = 10 Avant de faire la commande d'appel.



0
votes

Pour obtenir tous les parents de l'enfant sélectionné (user_id = 3 dans cet exemple):

xxx

Pour obtenir tous les enfants d'un utilisateur sélectionné

xxx

Ceci nécessite la fonction suivante

xxx xxx

extrémité

Cet exemple utilise fortement les variables de session que de nombreux utilisateurs SQL peuvent être inconnus. Voici un lien qui peut fournir une idée: variables de session


2 commentaires

Curieux Si vous avez testé cela vous-même? Par exemple, votre fonction accepte un paramètre 'valeur' ​​mais ne l'utilise jamais.


@DTest MySQL ignore la clause non déterministe dans la définition de la fonction, cache sa valeur de retour et ne l'appelle pas en réalité si elle s'appelle avec les mêmes arguments. Donc, il est juste là pour rendre MySQL exécuter la fonction. J'ai utilisé cet exemple de fonction / de requête avant sur un jeu de données légèrement différent et je viens de l'adapter à l'OP.



1
votes

C'est l'un des meilleurs articles que j'ai vus pour expliquer la méthode "modifiée de traversée d'arborescence de l'arborescence de l'arborescence de l'arbre" de stocker des données de type arbores dans une base de données de style SQL.

http://www.sitepoint.com/hierarchical-data-database/

Le matériel MPT commence Page 2.

essentiellement, vous stockez une valeur "gauche" et "droite" pour chaque noeud dans l'arborescence, de manière à obtenir tous les enfants de parentéa , Vous obtenez la gauche et la droite pour la parentéa, puis xxx


2 commentaires

+1 C'est génial pour l'efficacité, bien que je quitte toujours le champ des parents afin que je puisse vous reconstruire s'il y a un mauvais insert.


En effet, parent, je suis important pour les reconstitutions. J'utilise également MPT pour une table d'enregistrement de 20k, de sorte que les insertions peuvent être lentes, donc si je insère de nombreux enregistrements, je ne fais que les inserts que les insertions ne mettent ensuite à jour les masses de gauche et des droits én par la suite.