Моделирование Rails: преобразование HABTM в has_many: через - PullRequest
5 голосов
/ 09 ноября 2009

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

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

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

Спасибо!

Justin

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

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

Ответы [ 3 ]

6 голосов
/ 09 ноября 2009

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

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

Может быть, смотрите здесь для более подробной информации.

Edit:

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

add_column :table, :id, :primary_key

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

3 голосов
/ 10 ноября 2009

Вам необходимо создать новый столбец, заполнить его значениями PK, а затем создать 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.

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

1 голос
/ 09 ноября 2009

Используйте alter table для добавления столбца pk.

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

После завершения сценария снова используйте alter table, чтобы задать для столбца primary_key и автоинкремент, установив начальное значение приращения в table_size + 1.

...