2009-10-17 8 views
4

Si je le tableau suivant & données pour nous permettre d'utiliser le sort_index pour le tri:MySQL mettre à jour une colonne d'index de tri pour déplacer des éléments

CREATE TABLE `foo` (
    `id` INT(11) NOT NULL AUTO_INCREMENT, 
    `bar_id` INT(11) DEFAULT NULL, 
    `sort_index` INT(11) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
); 

INSERT INTO `foo` (`bar_id`, `sort_index`) VALUES 
(1,1),(1,2),(1,3),(1,4), 
(2,1),(2,2),(2,3),(2,4),(2,5); 

Je veux être en mesure de faire ce qui suit dans le plus efficace manière:

  1. Déplacer une entrée de foo à une position donnée (scope par le bar_id)
    • Assurez-vous que le sort_index est toujours 1 indexé et n'a pas les lacunes
    • Vous devriez être en mesure de déplacer des éléments au début et à la fin de la liste et la règle n ° 2 doit encore être appliqué
    • Il devrait être entièrement fait dans les requêtes et aussi peu que possible (que les ensembles peuvent être très grandes et en boucle sur les faire UPDATE individuels s est pas idéal)

pour clarifier ce que je suis en train de faire, laisse supposer la table était vide donc nous avons la les données suivantes:

id | bar_id | sort_index 
1 | 1  | 1 
2 | 1  | 2 
3 | 1  | 3 
4 | 1  | 4  
5 | 2  | 1 
6 | 2  | 2 
7 | 2  | 3 
8 | 2  | 4 
9 | 2  | 5 

Ensuite, si nous devions faire les mouvements suivants

  • foo 1 à sort_index 3
  • foo 7 à sort_index 1
  • foo 5 à sort_index 5

Nous devrions obtenir le les données suivantes:

id | bar_id | sort_index 
1 | 1  | 3 
2 | 1  | 1 
3 | 1  | 2 
4 | 1  | 4  
5 | 2  | 5 
6 | 2  | 2 
7 | 2  | 1 
8 | 2  | 3 
9 | 2  | 4 

Et SELECT * FROM foo ORDER BY bar_id, sort_index; nous donne:

id | bar_id | sort_index 
2 | 1  | 1 
3 | 1  | 2 
1 | 1  | 3 
4 | 1  | 4 
7 | 2  | 1 
6 | 2  | 2 
8 | 2  | 3 
9 | 2  | 4 
5 | 2  | 5 
+0

Pour clarifier votre question: étant donné les insertions ci-dessus, vous voulez insérer une autre ligne avec 'bar_id' = 1 au début, entraînant des mises à jour (de la colonne' sort_index') de toutes les lignes suivantes où 'bar_id' est 1? – tangens

+0

Pour résumer vos besoins, pour tout ensemble de "bar_id", le sort_index DOIT partir de zéro et augmenter de 1 jusqu'au plus grand numéro de sort_index.Et vous voulez faire cela entièrement en MySQL pour toutes les opérations de déplacement/ajout/suppression? –

Répondre

3

Vous devriez être en mesure de le faire en une seule requête: quelque chose le long des lignes de UPDATE foo SET sort_index = sort_index + 1 WHERE bar_id == b AND sort_index < s1 AND sort_index >= s2, où b est le bar_id de la ligne à déplacer, s1 est le sort_index actuel cette ligne, et s2 est le sort_index que vous souhaitez déplacer. Ensuite, vous devez simplement changer le sort_index de la rangée.

Vous voudrez probablement faire les deux requêtes dans une transaction. En outre, il pourrait accélérer les choses si vous avez créé un index sur le sort_index en utilisant quelque chose comme CREATE INDEX foo_index ON foo (sort_index).

(Soit dit en passant, ici je suppose que vous ne voulez pas faire double emploi sort_index valeurs dans une donnée bar_id, et que l'ordre relatif des lignes ne doit jamais être changé, sauf explicitement. Si vous ne avez pas besoin, la solution est encore plus simple.)

+0

C'est assez chic et fonctionne presque parfaitement. Cependant, cela ne fonctionne pas si je veux déplacer un élément à la fin de la liste, car je me retrouve avec 2 avec la même finition sort_index et aucun remplissant l'ancien sort_index (par exemple, si je déplace un élément de 3 à 5 finir avec 2 avec sort_index de 5 et rien avec un 3). – DEfusion

+1

En fait il y a des situations (comme passer à la fin de la liste) où vous devez utiliser ceci: UPDATE foo SET sort_index = sort_index - 1 OERE bar_id == b ET sort_index> s1 ET sort_index <= s2 – DEfusion

+0

Ah oui, bien sûr. En fait, ce n'est pas seulement lorsque vous le déplacez à la fin de la liste, c'est à chaque fois que vous le faites avancer. – David

Questions connexes