2010-09-28 3 views
7

J'ai une table des profils d'utilisateurs. Chaque utilisateur peut avoir plusieurs profils et l'utilisateur a la possibilité d'organiser l'ordre dans lequel ils seront affichés dans une grille.Quel serait le meilleur moyen de stocker l'ordre des enregistrements dans SQL

Il y a 2 tables utilisateurs et profils (1: M)

J'ai ajouté une colonne orderby à la table des utilisateurs où seront des valeurs telles que 1,2,3 ..

Jusqu'à présent, il semble être bien. Mais quand un utilisateur va changer l'ordre du dernier enregistrement pour être le premier, je dois parcourir tous les enregistrements et incrémenter leurs valeurs +1. Cela me semble plutôt moche.

Existe-t-il une solution plus pratique pour ce genre de situation?

Répondre

3

La meilleure solution est celle qui reflète la fonctionnalité, et c'est une simple liste d'entiers. Garder la liste dans l'ordre est seulement quelques instructions SQL, et plus facile à comprendre que les autres solutions suggérées (flottants, entiers gapped). Si vos listes étaient très volumineuses (par dizaines de milliers), des considérations de performances pourraient entrer en jeu, mais je suppose que ces listes ne sont pas si longues.

+0

+1 Lorsque la sémantique du problème correspond à celle de la solution, il y a moins d'endroits où cacher les bogues. –

8

Laissez des espaces dans la séquence ou utilisez un type de données décimal plutôt qu'entier.

+2

De préférence le second. –

1

Lorsqu'un utilisateur ajoute des profils, définissez le numéro de commande de chaque nouveau profil sur le précédent +1000000. par exemple. de commencer par:

p1 1000000 
p2 2000000 
p3 3000000 

Lorsque réordonnancement, réglez la commande du profil au milieu des deux, il va entre:

p1 1000000 
p2 2000000 
p3 1500000 

Cela donne l'ordre p1, p3, p2

3

Que diriez-vous d'utiliser des points flottants pour la commande par colonne? De cette façon, vous pouvez toujours presser un profil entre deux autres, sans avoir à changer ces deux valeurs. Par exemple, si je veux placer le profil A entre les profils B (ordervalue 1) et C (ordervalue 2), je peux affecter ordervalue 1.5 à A. Pour le placer en haut, où avant le sommet avait l'habitude d'avoir ordervalue dire 1, vous peut utiliser ordervalue 0.5

Il n'y a aucune raison d'avoir des entiers pour orderby et aucune raison d'avoir des incréments de 1 entre l'ordre des profils.

+0

+1 - Battez-moi. – JNK

+4

Disons que vous avez 3 enregistrements, vous leur attribuez des numéros 1,2,3. Ensuite, vous réorganiser le dernier à être entre les deux premiers, et obtenir le numéro de 1,5 pour cela. Ensuite, répétez le processus, et chaque fois que vous le rapprochez de 1, comme 1,25, 1,125, etc. Jusqu'à ce que vous ayez atteint la limite de précision, et cela arrive très bientôt, 50 itérations. Ensuite, vous avez un bug méchant ... :( – Hrissan

1

Je pense que l'idée de laisser des écarts entre les commandes est intéressante mais je ne sais pas si c'est une solution "plus pratique" pour votre problème.

Je pense que vous feriez mieux de simplement mettre à jour votre colonne order by. Parce que vous devrez encore déterminer les lignes dans lesquelles les états se sont déplacés et que faire si deux états sont positionnés (calculez-vous le nouvel ordre par valeur pour le premier puis le second). Que se passe-t-il si l'écart n'est pas assez grand?

Il ne devrait pas être si fastidieux d'énumérer l'ordre dans lequel ils l'ont placé et de mettre à jour chaque enregistrement dans l'ordre.

2

Si l'ensemble de données est petit (ce qui semble être le cas), je préférerais utiliser une liste normale d'entiers et les mettre à jour par lots lorsqu'un profil obtient une nouvelle position.Cela reflète mieux la fonctionnalité de l'application.

Dans Sql Server, pour le tableau suivant User_Profiles (user_id, profile_id, position), je serais quelque chose comme ceci:

--# The variables are: 
--# @user_id - id of the user 
--# @profile_id - id of the profile to change 
--# @new_position - new position that the profile will take 
--# @old_position - current position of the profile 

select @old_position = position 
from User_Profiles where 
user_id = @user_id and profile_id = @profile_id 

update p set position = pp.new_position 
from User_Profiles p join (
    select user_id, profile_id, 
    case 
    when position = @old_position then @new_position 
    when @new_position > @old_position then --# move up 
     case 
     when @old_position < position and 
      position <= @new_position 
     then position - 1 
     else position 
     end 
    when @new_position < @old_position then --# move down 
     case 
     when position < @old_position and 
      @new_position <= position 
     then position + 1 
     else position 
     end 
    else position --# the same 
    end as new_position 
    from User_Profiles p where user_id = @user_id 
) as pp on 
p.user_id = pp.user_id and p.profile_id = pp.profile_id 
0

Je pense qu'au lieu de maintenir l'ordre dans la colonne orderby vous pouvez introduire concept linklist à votre conception. Ajoutez une colonne comme nextId qui contiendra le prochain profil dans la chaîne. Lorsque vous interrogez le tableau profiles vous pouvez trier les profils dans votre code (java, C#, etc)

Questions connexes