2009-11-09 3 views
5

Я занимаюсь ремонтом существующего сайта Rails, и у меня возникают проблемы, связанные со многими ассоциациями. Похоже, что сайт был изначально построен с использованием has_and_belongs_to_many для нескольких отношений, которые с тех пор усложнились в бизнес-логике, поэтому мне нужно использовать has_many :through вместо этого, чтобы поддерживать дополнительные поля в таблице отношений. Тем не менее, таблица соединений, которая изначально использовалась для HABTM, не имеет первичного ключа, и я должен добавить ее для поддержки отдельного моделирования отношений, используя has_many :through.Моделирование рельсов: преобразование HABTM в has_many: через

Каков наилучший способ добавления первичного ключа в существующую таблицу с большим количеством данных? Есть ли другой способ сделать то, что я пытаюсь сделать?

Кстати, система работает на Oracle.

Спасибо!

Джастин

UPDATE 11/9/09 3:58 вечер: Я не эксперт Oracle и был затеряться в дебрях версий Oracle, в не нулевом, автоприращении, и так далее. Первоначально я пытался сделать то, что рекомендовал Майк и Кори, добавив новое поле в качестве первичного ключа, но Oracle не позволит мне добавить ненулевое поле в непустую таблицу (ORA-01758). Затем я экспортировал данные как SQL, сбросил строки, добавил PK и установил, что он не является нулевым, а затем попытался импортировать данные, но я продолжал получать ошибки до мелодии «не могу вставить NULL в id ...» (ОР-01400).

Наконец, я попытался использовать миграцию, как предлагает Кори в своем комментарии, но rake ударил те же ошибки, что и Oracle, когда я изменил базу данных вручную («не могу добавить ненулевое поле в непустую таблицу»). Я очистил таблицу, выполнил миграцию (которая работала), а затем попыталась повторно импортировать данные, но в то же время у меня были те же ошибки, что и в прошлый раз, когда я пытался импортировать («не могу вставить NULL в id ...»). Как сохранить мои данные и добавить необходимые мне первичные ключи? Я знаю, что была предложена возможность написания рейк-задачи, но я не уверен, как действовать на этом фронте. Есть идеи?

+0

См. Также последние вопросы и ответы: http://stackoverflow.com/questions/16159134/how-to-migrate-has-and-belongs-to-many-to-has-many-through/29067732# 29067732 – MZB

ответ

3

Вам нужно создать новый столбец, заполнить его значениями PK, а затем создать ПК на новой колонке, например:

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. 

В зависимости от того, сколько строк в таблице это может занять а для заполнения значений последовательности, но это сработает.

6

При использовании базы данных оракула я использую SQL Developer. Просто создайте столбец и добавить ограничение в базу данных, например:

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

Может видеть here для некоторых более подробно.

Edit:

Теперь, когда я переосмыслить это, вы должны быть в состоянии сделать это в миграции

add_column :table, :id, :primary_key 

Затем вам нужно посеять некоторые данные внутри миграции. Просто код ruby, который выполняет итерацию и добавляет ваш индекс. См. seed_fu и db-populate для получения справки. Rails 3 позволит вам засеять данные с помощью rake db: seed.

+0

Спасибо за ответ, Кори. Есть ли способ autopopulate id # для всех существующих ранее записей? – justinbach

+0

Я не знаю, как это сделать. Я бы просто создал задачу rake, которая выполняет итерацию через них и добавляет индекс, но я больше знаком с ruby, чем с SQL. Включение auto_increment добавит идентификатор после получения существующего набора данных. – coreypurcell

1

Используйте таблицу alter, чтобы добавить столбец pk.

Напишите сценарий для установки новых значений столбца pk инкрементально (какой-то цикл).

После выполнения сценария снова используйте таблицу alter, чтобы установить столбец в primary_key и auto-increment, установив начальное значение приращения в table_size + 1.