web-dev-qa-db-ja.com

Ectoで外部キーを変更する

私はすでに実行されてアップストリームに送信されたこのオリジナルの移行を持っています:

create table(:videos) do
  add :url, :string
  add :title, :string
  add :description, :text
  add :user_id, references(:users, on_delete: :nothing)

  timestamps
end
create index(:videos, [:user_id])

次に、user_idの外部キーをカスケード削除に変更して、ユーザーが削除されると、関連付けられている動画もすべて削除されるようにします。

次の移行を試しました:

alter table(:videos) do
  modify :user_id, references(:users, on_delete: :delete_all)
end

ただし、これによりエラーが発生します。

(Postgrex.Error) ERROR (duplicate_object): constraint "videos_user_id_fkey" for relation "videos" already exists

要件に応じてこの外部キーを変更する移行スクリプトを作成するにはどうすればよいですか?


[〜#〜]更新[〜#〜]

私は次の解決策に終わりました:

def up do
  execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
  alter table(:videos) do
    modify :user_id, references(:users, on_delete: :delete_all)
  end
end

def down do
  execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
  alter table(:videos) do
    modify :user_id, references(:users, on_delete: :nothing)
  end
end

これにより、ectoが制約の再作成を試みる前に制約が削除されます。

32
Thomas Dippel

alterを呼び出す前にインデックスを削除できます:

drop_if_exists index(:videos, [:user_id])
alter table(:videos) do
  modify :user_id, references(:users, on_delete: :delete_all)
end

反対のことは少しトリッキーです:

execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
create_if_not_exists index(:videos, [:user_id])
18
Gazler

これがEctoにいつ追加されたかはわかりませんが、少なくとも2.1.6では、生のSQLは必要なくなりました。 drop/1現在 制約をサポートdrop_if_exists/1はしません):

def up do
  drop constraint(:videos, "videos_user_id_fkey")
  alter table(:videos) do
    modify :user_id, references(:users, on_delete: :delete_all)
  end
end

def down do
  drop constraint(:videos, "videos_user_id_fkey")
  alter table(:videos) do
    modify :user_id, references(:users, on_delete: :nothing)
  end
end
27
Max Clarke

私は次の解決策に終わりました:

def up do
  execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
  alter table(:videos) do
    modify :user_id, references(:users, on_delete: :delete_all)
  end
end

def down do
  execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
  alter table(:videos) do
    modify :user_id, references(:users, on_delete: :nothing)
  end
end

これは、ectoが制約を再作成しようとする前に制約を削除します

質問からコピーしました。

8
Jesse Shieh

alter tableでは実現できないと思います。たとえば この答え に従って、PostgresはALTER TABLEステートメントの制約を変更することを許可していません。 MySQLでは制約の変更も許可されていません

最も簡単な方法は、フィールドを削除して、データがない場合はフィールドを元に戻すことです。それ以外の場合は、生のSQLを execute で使用する必要があります

2
tkowal