web-dev-qa-db-fra.com

Meilleur moyen de sauvegarder une liste commandée dans la base de données tout en conservant la commande

Je me demandais si quelqu'un avait une bonne solution à un problème que j'ai rencontré plusieurs fois au cours des dernières années.

J'ai un panier d'achat et mon client demande explicitement que sa commande soit importante. J'ai donc besoin de maintenir l'ordre dans la DB.

La manière évidente serait d'insérer simplement un champ OrderField où j'attribuerais le numéro 0 à N et de le trier de cette façon.

Mais cela rendrait la réorganisation plus difficile et je pense que cette solution est un peu fragile et me reviendra un jour.

(J'utilise C # 3,5 avec NHibernate et SQL Server 2005)

Je vous remercie

67
Tigraine

FWIW, je pense que la façon dont vous suggérez (c'est-à-dire la validation de la commande dans la base de données) n'est pas une mauvaise solution à votre problème. Je pense aussi que c'est probablement le moyen le plus sûr/le plus fiable.

24
Galwegian

Ok, voici ma solution pour rendre la programmation plus facile pour tous ceux qui se trouvent dans ce fil. l'astuce consiste à mettre à jour tous les index de commande au-dessus ou en dessous d'une insertion/suppression en une seule mise à jour.

Utilisation d'une colonne numérique (entier) dans votre table, prise en charge par les requêtes SQL

CREATE TABLE myitems (Myitem TEXT, id INTEGER PRIMARY KEY, orderindex NUMERIC);

Pour supprimer l'article à orderindex 6:

DELETE FROM myitems WHERE orderindex=6;    
UPDATE myitems SET orderindex = (orderindex - 1) WHERE orderindex > 6;

Pour échanger deux éléments (4 et 7):

UPDATE myitems SET orderindex = 0 WHERE orderindex = 4;
UPDATE myitems SET orderindex = 4 WHERE orderindex = 7;
UPDATE myitems SET orderindex = 7 WHERE orderindex = 0;

c'est-à-dire que 0 n'est pas utilisé, alors utilisez-le comme un mannequin pour éviter d'avoir un élément ambigu.

Pour insérer à 3:

 UPDATE myitems SET orderindex = (orderindex + 1) WHERE orderindex > 2;
 INSERT INTO myitems (Myitem,orderindex) values ("MytxtitemHere",3)
48
Kickaha

La meilleure solution est une liste doublement liée . O(1) pour toutes les opérations à l'exception de l'indexation. Rien ne peut cependant indexer SQL rapidement, sauf une clause where sur l'élément souhaité.

0,10,20 types échouent. Les colonnes de la séquence échouent. La colonne de séquence flottante échoue lors des déplacements de groupe.

La liste Doublement liée est identique aux opérations d'ajout, de suppression, de suppression de groupe, d'ajout de groupe, de déplacement de groupe. La liste chaînée unique fonctionne aussi bien. À mon avis, le double lien est mieux avec SQL. Une seule liste chaînée nécessite que vous ayez la liste complète.

31
sean wagner

Que diriez-vous d'utiliser une implémentation de liste chaînée? Le fait d'avoir une colonne contiendra la valeur (numéro de commande) de l'article suivant. Je pense que c'est de loin le plus facile à utiliser lors de l'insertion de commandes entre les deux. Pas besoin de renuméroter.

10
Js.

Malheureusement, il n'y a pas de solution miracle pour cela. Vous ne pouvez pas garantir l'ordre d'une instruction SELECT SANS clause order by. Vous devez ajouter la colonne et programmer autour d'elle.

Je ne sais pas que je recommanderais d'ajouter des lacunes dans la séquence de commande, en fonction de la taille de vos listes et des hits sur le site, vous pourriez gagner très peu pour les frais généraux de gestion de la logique (vous auriez encore besoin pour répondre à l’occasion où toutes les lacunes ont été épuisées). Je regarderais de près pour voir quels avantages cela vous apporterait dans votre situation.

Désolé, je ne peux rien offrir de mieux, j'espère que cela vous a aidé.

5
Binary Worrier

Je ne recommanderais pas du tout l'approche A, AA, B, BA, BB. Il y a beaucoup de traitement supplémentaire impliqué pour déterminer la hiérarchie et insérer des entrées entre les deux n'est pas amusant du tout.

Ajoutez simplement un OrderField, entier. N'utilisez pas d'espaces, car vous devez alors soit travailler avec une "étape" non standard sur votre prochaine insertion centrale, soit vous devrez resynchroniser votre liste en premier, puis ajouter une nouvelle entrée.

Il est facile de réorganiser 0 ... N, et si vous pouvez utiliser des méthodes de tableau ou des méthodes de liste en dehors de SQL pour réorganiser la collection dans son ensemble, puis mettez à jour chaque entrée, ou vous pouvez comprendre où vous insérez, et +1 ou -1 chaque entrée après ou avant en conséquence.

Une fois que vous aurez écrit une petite bibliothèque, ce sera un jeu d'enfant.

4
Adam

Je l'ai résolu de façon pragmatique comme ceci:

  1. L'ordre est défini dans l'interface utilisateur.

  2. Le backend reçoit une demande POST qui contient les ID et la position correspondante de chaque élément de la liste.

  3. Je lance une transaction et met à jour la position pour chaque ID.

Terminé.

La commande est donc chère mais la lecture de la liste commandée est super bon marché.

1
Bijan

Je voudrais simplement insérer un champ de commande. C'est le moyen le plus simple. Si le client peut réorganiser les champs ou si vous devez insérer au milieu, réécrivez simplement les champs de commande pour tous les articles de ce lot.

Si au bout du compte, vous trouvez cette limitation en raison de performances médiocres sur les insertions et les mises à jour, il est possible d'utiliser un champ varchar plutôt qu'un entier. Cela permet un niveau de précision assez élevé lors de l'insertion. Par exemple, pour insérer entre les articles "A" et "B", vous pouvez insérer un article commandé comme "AA". C'est presque certainement exagéré pour un panier d'achat.

1
Jack Ryan

À un niveau d'abstraction au-dessus du panier Articles, disons CartOrder (qui a 1-n avec CartItem), vous pouvez conserver un champ appelé itemOrder qui pourrait être juste une liste d'ID (PK) séparée par des virgules des enregistrements cartItem pertinents. Ce sera au niveau de la couche d'application que vous devrez analyser cela et organiser vos modèles d'articles en conséquence. Le gros avantage de cette approche sera en cas de remaniements de commande, il peut ne pas y avoir de modifications sur les objets individuels, mais comme la commande est conservée en tant que champ d'index dans les lignes de la table des éléments de commande, vous devrez émettre une commande de mise à jour pour chacun des lignes mettant à jour leur champ d'index. Veuillez me faire part de vos critiques sur cette approche, je suis curieux de savoir de quelle manière cela pourrait échouer.

1
redzedi

Je recommanderais de garder des lacunes dans le numéro de commande, donc au lieu de 1,2,3 etc., utilisez 10,20,30 ... Si vous avez juste besoin d'insérer un élément de plus, vous pouvez le mettre à 15, plutôt que de tout réorganiser à ce moment.

0
harriyott

Eh bien, je dirais que la réponse courte est:

Créez une clé primaire d'auto-identité dans la table cartcontents, puis insérez des lignes dans le bon ordre descendant. Ensuite, en sélectionnant dans le tableau avec ordre par la colonne d'auto-identité de la clé primaire, vous obtiendrez la même liste. Ce faisant, vous devez supprimer tous les articles et les réinsérer en cas de modification du contenu du panier. (Mais c'est toujours une manière assez propre de le faire) Si ce n'est pas possible, alors allez avec la colonne de commande comme suggéré par d'autres.

0
sindre j