Question

J'ai une table de base de données MySQL avec cette structure:

table
    id INT NOT NULL PRIMARY KEY
    data ..
    next_id INT NULL

Je dois récupérer les données dans l'ordre de la liste chaînée. Par exemple, étant donné ces données:

 id | next_id
----+---------
  1 |       2
  2 |       4
  3 |       9
  4 |       3
  9 |    NULL

I besoin de chercher les lignes pour id = 1, 2, 4, 3, 9, dans cet ordre. Comment puis-je faire avec une requête de base de données? (Je peux le faire à la fin du client. Je suis curieux de savoir si cela peut se faire du côté de la base de données. Ainsi, en disant qu'il est impossible est correct (une preuve suffisante donnée)).

Il serait agréable d'avoir un point de terminaison, ainsi (arrêt par exemple après 10 récupérations, ou quand une condition sur la ligne tourne vrai), mais ce n'est pas une exigence (qui peut être fait sur le côté client). I (espoir I) ne pas besoin de vérifier les références circulaires.

Était-ce utile?

La solution

Certaines marques de base de données (par exemple Oracle, Microsoft SQL Server) en charge la syntaxe SQL supplémentaire pour exécuter « requêtes récursives » mais MySQL ne supporte pas une telle solution.

Le problème que vous décrivez est le même que celui qui représente une structure arborescente dans une base de données SQL. Vous avez juste un long, arbre maigre.

Il existe plusieurs solutions pour le stockage et la récupération de ce genre de structure de données à partir d'un SGBDR. Voir quelques-unes des questions suivantes:


Puisque vous mentionnez que vous souhaitez limiter la « profondeur » renvoyée par la requête, vous pouvez y parvenir en interrogeant la liste de cette façon:

SELECT * FROM mytable t1
 LEFT JOIN mytable t2 ON (t1.next_id = t2.id)
 LEFT JOIN mytable t3 ON (t2.next_id = t3.id)
 LEFT JOIN mytable t4 ON (t3.next_id = t4.id)
 LEFT JOIN mytable t5 ON (t4.next_id = t5.id)
 LEFT JOIN mytable t6 ON (t5.next_id = t6.id)
 LEFT JOIN mytable t7 ON (t6.next_id = t7.id)
 LEFT JOIN mytable t8 ON (t7.next_id = t8.id)
 LEFT JOIN mytable t9 ON (t8.next_id = t9.id)
 LEFT JOIN mytable t10 ON (t9.next_id = t10.id);

Il va effectuer comme de la mélasse, et le résultat va revenir sur une seule ligne (par liste chaînée), mais vous aurez le résultat.

Autres conseils

Si ce que vous essayez d'éviter est d'avoir plusieurs requêtes (un pour chaque nœud) et vous êtes en mesure d'ajouter des colonnes, vous pouvez alors une nouvelle colonne qui relie au nœud racine. De cette façon, vous pouvez tirer dans toutes les données à la fois par l'ID racine, mais vous aurez toujours à trier la liste (ou arbre) du côté client.

Donc, dans c'est par exemple vous auriez:

 id | next_id | root_id
----+---------+---------
  1 |       2 |       1
  2 |       4 |       1
  3 |       9 |       1
  4 |       3 |       1
  9 |    NULL |       1

Bien sûr, l'inconvénient de cette opposition à des listes chaînées traditionnelles ou des arbres est que la racine ne peut pas changer sans écrire sur un ordre de grandeur de O (n) où n est le nombre de noeuds. En effet, vous devez mettre à jour l'ID racine pour chaque noeud. Heureusement que vous devriez toujours être en mesure de le faire dans une requête de mise à jour unique, sauf si vous divisez une liste / arbre au milieu.

Ceci est une solution moins et plus d'une solution mais, pour une liste linéaire (plutôt que l'arbre Bill Karwin mentionné), il pourrait être plus efficace d'utiliser une colonne de tri sur votre liste. Par exemple:

TABLE `schema`.`my_table` (
    `id` INT NOT NULL PRIMARY KEY,
    `order` INT,
    data ..,
    INDEX `ix_order` (`sort_order` ASC)
);

Alors:

SELECT * FROM `schema`.`my_table` ORDER BY `order`;

Ceci présente l'inconvénient d'inserts plus lents (vous devez repositionner tous les éléments triés depuis le point d'insertion), mais devrait être rapide pour la récupération car la colonne de commande est indexée.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top