2010-05-08 4 views
2

J'ai ici affaire à une table MySQL qui est malencontreusement codée. Au lieu d'utiliser une table d'incrémentation automatique en tant que clé, elle utilise une colonne de nombres décimaux pour préserver l'ordre (il n'est donc pas trop difficile d'insérer de nouvelles lignes tout en conservant une clé primaire et un ordre). Avant de passer en revue et de refaire cette table à quelque chose de plus sain d'esprit, j'ai besoin de comprendre comment le re-clé sans tout casser. Ce que je voudrais faire est quelque chose qui prend une liste de doubles (les clés actuelles) et sort une liste d'entiers (qui peuvent être transformés en doubles pour rekeying).Le moyen le plus rapide de modifier une table avec des nombres décimaux dans MySQL?

Par exemple, l'entrée {1.00, 2.00, 2.50, 2.60, 3.00} donnerait la sortie {1, 2, 3, 4, 5).

Puisque c'est une base de données, je dois aussi être en mesure de mettre à jour les lignes bien:

UPDATE table SET `key`='3.00' WHERE `key`='2.50'; 

Quelqu'un peut-il penser à un algorithme rapide de le faire? Ma pensée actuelle est de lire tous les doubles dans un vecteur, de prendre la taille du vecteur et de sortir un nouveau vecteur avec des valeurs de 1 => doubleVector.size. Cela semble assez lent, puisque vous ne voudriez pas lire chaque valeur dans le vecteur si, par exemple, seuls les derniers n/100 éléments devaient être modifiés.

Je pense qu'il y a probablement quelque chose que je peux faire en place, car seules les valeurs après le premier non-entier doivent être modifiées, mais je ne peux rien comprendre pour que je puisse me mettre à jour placer aussi bien. Par exemple, la définition de 2.60 à 3.00 la première fois que vous voyez 2.50 dans la liste des clés d'origine entraînerait une erreur, car la valeur de clé 3.00 est déjà utilisée pour la table.


Edit: Je suppose que ce abstracts vraiment à ceci:

je besoin d'un moyen de convertir une carte ordonnée calée en double dans une carte ordonnée calée avec des nombres entiers, où, à aucun moment il jamais existe deux valeurs pour une clé (qui est une violation d'une carte de toute façon).

+1

Quelle est la taille de cette table? –

+0

Eh bien, il y a beaucoup de tables de cette forme. Ils vont de la taille d'environ 100 lignes à plus d'un millier. – javanix

Répondre

3

Je suppose que vous serez en mesure de prendre la base de données vers le bas à un moment donné pour effectuer cette conversion.

Note: Je ne suis PAS un utilisateur de MySQL. Ma DB de choix est PostgreSQL, donc il peut y avoir des ERREURS DE SYNTAXE ici entre la façon dont MySQL le fait et Pg le fait. Mais cela devrait vous donner une bonne idée.

Tout d'abord, faire une table de correspondance qui associe vieilles clés à nouveau:

create table keymap (
    oldkey decimal, 
    newkey integer autoincrement 
) 

Assurez-vous que l'indice keymap parce que nous allons être en abondance sur elle lookups.

create unique index keymap_oldkey on keymap(oldkey); 

Remplissez ensuite avec les anciennes clés et laisser MySQL créer les nouvelles:

insert into keymap 
    select distinct `key` from fribbles order by `key` 

Maintenant, vous aurez Keymap toutes les anciennes clés, et parce que vous n'avez pas spécifié une nouvelle clé , l'auto-incrément de la colonne newkey s'affichera et votre tableau ressemblera à ceci.

oldkey newkey 
---------------- 
1.5  1 
1.6  2 
1.93  3 
3.1  4 

Maintenant, ajoutez une colonne newkey à vos tables qui en ont besoin

alter table fribbles add column newkey integer 

Ne pas faire l'auto-incrémentation, car sinon il se peuplé à alter temps, et on n'a pas besoin que .

Maintenant, enfin, mettre à jour la table fribbles:

update fribbles f 
    set newkey = (select newkey from keymap m where m.oldkey = f.`key`) 

Enfin, maintenant que vous avez newkey peuplé, vous pouvez déposer l'ancien.

alter table fribbles drop column `key`; 
alter table fribbles alter column newkey rename to `key`; 

J'espère que cela vous donnera un plan d'attaque décent.

1

Je voudrais simplement ajouter une colonne int (qui autorise les valeurs NULL) à la table, puis effectuer une exécution basée sur le curseur ou le code où trier par la colonne PK double whack-out d'origine, puis parcourir les enregistrements une valeur incrémentée dans la nouvelle colonne int. Ensuite, mettez à jour la table en remplaçant PK par la nouvelle colonne int et en supprimant l'ancien PK.

"Ici", comme on dit en France.

Questions connexes