2009-11-09 15 views
5

Je fais des travaux de maintenance sur un site Rails existant et j'ai quelques problèmes provenant d'associations many-to-many. Il semble que le site a été initialement construit en utilisant has_and_belongs_to_many pour quelques relations qui se sont compliquées depuis dans la logique métier, donc je dois utiliser has_many :through à la place pour supporter des champs supplémentaires dans la table de relation. Cependant, la table de jointure initialement utilisée pour HABTM n'a pas de clé primaire, et je dois en ajouter une pour prendre en charge la modélisation de relation séparée en utilisant has_many :through.Modélisation de Rails: convertir HABTM en has_many: à travers

Quelle est la meilleure façon d'ajouter une clé primaire à une table existante avec beaucoup de données? Y a-t-il une autre façon de faire ce que j'essaie de faire? Par ailleurs, le système fonctionne sur Oracle.

Merci!

Justin

MISE À JOUR 11/9/09 15h58: Je ne suis pas un expert Oracle et ont été se perdre dans les terres sauvages des versions d'Oracle de non nulle, auto-incrément, et ainsi de suite. Au début, j'ai essayé de faire ce que Mike et Corey recommandaient en ajoutant un nouveau champ comme clé primaire, mais Oracle ne me laisserait pas ajouter un champ non nul à une table non vide (ORA-01758). J'ai alors exporté les données comme SQL, ai laissé tomber les rangées, ai ajouté le PK et l'ai établi pour non-nul, alors ai essayé d'importer les données, mais j'ai continué à obtenir des erreurs au motif de "ne peut pas insérer NULL dans l'id ..." (ORA-01400). Enfin, j'ai essayé d'utiliser une migration comme le suggère Corey dans son commentaire, mais rake a rencontré les mêmes erreurs qu'Oracle lançait quand j'ai modifié manuellement la base de données ("impossible d'ajouter un champ non nul à une table non vide"). J'ai effacé la table, exécuté la migration (qui a fonctionné), puis essayé de réimporter les données, mais j'ai eu les mêmes erreurs la dernière fois que j'avais essayé d'importer ("impossible d'insérer NULL dans l'id ..."). Comment puis-je sauvegarder mes données et ajouter les clés primaires dont j'ai besoin? Je sais que la possibilité d'écrire une tâche râteau a été suggérée, mais je ne suis pas sûr de savoir comment procéder sur ce front. Des idées?

+0

Voir aussi cette question plus récente et ses réponses: http://stackoverflow.com/questions/16159134/how-to-migrate-has-and-belongs-to-many-to-has-many-through/29067732# 29067732 – MZB

Répondre

3

Vous devez créer la nouvelle colonne, le remplir avec les valeurs de PK, puis créer un PK sur la nouvelle colonne, par exemple:

SQL> create table no_pk_tab (c1 varchar2(10), c2 varchar2(10)) 
Table created. 
SQL> insert into no_pk_tab values ('one', 'one') 
1 row created. 
SQL> insert into no_pk_tab values ('two', 'two') 
1 row created. 

SQL> alter table no_pk_tab add (id integer) 
Table altered. 

SQL> create sequence no_pk_seq 
start with 1 
increment by 1 
Sequence created. 

SQL> update no_pk_tab set id = no_pk_seq.nextval 
2 rows updated. 
SQL> select * from no_pk 

C1   C2    PK_COL 
---------- ---------- ---------- 
one  one     1 
two  two     2 

2 rows selected. 

SQL> alter table no_pk add primary key (pk_col) using index 
Table altered. 

Selon le nombre de lignes dans votre table, il peut prendre tandis que pour remplir les valeurs de séquence, mais cela va fonctionner.

6

J'utilise SQL Developer lors de l'administration d'une base de données Oracle. Il suffit de créer la colonne et ajoutez une contrainte à la base de données par exemple:

sql> alter table Employee add constraint Employee_pk primary key(Employee_ID); 

voir Peut-être here pour un peu plus en détail.

Edit:

Maintenant que je repense cela, vous devriez être en mesure de le faire dans une migration

add_column :table, :id, :primary_key 

Vous devez ensuite semer des données à l'intérieur de la migration. Juste du code ruby ​​qui traverse et ajoute votre index. Voir seed_fu et db-populate pour l'aide. Rails 3 vous permettra de graver des données avec rake db: seed.

+0

Merci pour la réponse, Corey. Existe-t-il un moyen d'autopopuler les numéros d'identification pour tous les enregistrements préexistants? – justinbach

+0

Je ne connais pas de façon automatisée de le faire. Je voudrais juste créer une tâche rake qui itère à travers eux et ajoute l'index, mais je suis plus familier avec ruby ​​que SQL. En activant auto_increment, vous ajouterez les identifiants après avoir récupéré votre ensemble de données existant. – coreypurcell

1

Utilisez la commande alter table pour ajouter la colonne pk.

Ecrivez un script pour définir les nouvelles valeurs de colonne PK de manière incrémentielle (une sorte de boucle).

Une fois le script terminé, modifiez de nouveau la table pour définir la colonne sur primary_key et auto-increment, en définissant la valeur de début de l'incrément sur table_size + 1.