【问题标题】:SQLite3::SQLException: duplicate column name: User_id: ALTER TABLE "comments" ADD "User_id" integer/SQLite3::SQLException: 重复列名:User_id: ALTER TABLE "comments" ADD "User_id" integer/
【发布时间】:2014-11-04 12:28:57
【问题描述】:

我运行了命令

rails g migration AddUser_idToComments User_id:string

然后我发现 User_id 应该是一个整数,所以我跑了

rails g migration AddUser_idToComments User_id:integer --force 认为它会覆盖初始命令。

但是现在,我收到了这个错误:

``` louismorin$ rake db:迁移 == 20140910155248 AddIndexToComments:迁移 =============================== -- add_column(:cmets, :Index, :string) -> 0.0069 秒 == 20140910155248 AddIndexToComments: 迁移 (0.0070s) ======================

== 20140910181022 AddUserIdToComments: 迁移 ============================== -- add_column(:cmets, :User_id, :integer) 耙中止! StandardError:发生错误,此迁移和所有后续迁移已取消:

SQLite3::SQLException: 重复列名:User_id: ALTER TABLE "cmets" ADD "User_id" integer/Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_cmets.rb:3:in change' ActiveRecord::StatementInvalid: SQLite3::SQLException: duplicate column name: User_id: ALTER TABLE "comments" ADD "User_id" integer /Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_comments.rb:3:inchange' SQLite3::SQLException:重复的列名:User_id /Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_cmets.rb:3:in `change' 任务:TOP => db:migrate (通过使用 --trace 运行任务查看完整跟踪) ```

这是我的 schema.rb 文件

``` ActiveRecord::Schema.define(version: 20140910155210) 做

create_table "comments", force: true do |t|
  t.text     "body"
  t.integer  "post_id"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.string   "User_Id"
end

add_index "comments", ["post_id"], name: "index_comments_on_post_id"

create_table "posts", force: true do |t|
  t.string   "title"
  t.text     "body"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.integer  "user_id"
  t.integer  "topic_id"
end

add_index "posts", ["topic_id"], name: "index_posts_on_topic_id"
add_index "posts", ["user_id"], name: "index_posts_on_user_id"

create_table "topics", force: true do |t|
  t.string   "name"
  t.boolean  "public",      default: true
  t.text     "description"
  t.datetime "created_at"
  t.datetime "updated_at"
end

create_table "users", force: true do |t|
  t.string   "email",                  default: "", null: false
  t.string   "encrypted_password",     default: "", null: false
  t.string   "reset_password_token"
  t.datetime "reset_password_sent_at"
  t.datetime "remember_created_at"
  t.integer  "sign_in_count",          default: 0,  null: false
  t.datetime "current_sign_in_at"
  t.datetime "last_sign_in_at"
  t.string   "current_sign_in_ip"
  t.string   "last_sign_in_ip"
  t.string   "confirmation_token"
  t.datetime "confirmed_at"
  t.datetime "confirmation_sent_at"
  t.string   "unconfirmed_email"
  t.string   "name"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.string   "role"
  t.string   "avatar"
  t.string   "Image"
end

add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique:     true

end

```

【问题讨论】:

  • SQLite 不直接支持更改列的类型。
  • Louis -- 你能在上面添加你的db/schema.rb 文件吗?查看您的数据库当前的样子会很有帮助。
  • 是的。混合的 CamelCase_snake_case 迁移名称似乎混淆了 Rails,导致大写的列名称 User_id。只是要记住的一件事。您是否尝试过以下方法?

标签: ruby sqlite


【解决方案1】:

由于该错误,您的第二次迁移(更改列类型)没有运行。如果该迁移只是为了更改那一列,那么我们可以删除它生成的文件并重试。

如果您在该列中还没有任何您关心的数据,那很容易:

rails g migration ChangeTypeOfUserIdOnComments

此迁移名称并不特殊。还不如DoWhateverIWant

然后,将创建的迁移的更改方法编辑为如下内容:

def change
  remove_column :comments, :user_id
  add_column :comments, :user_id, :integer
  add_index :comments, :user_id
end

当您随后运行未运行的迁移 rake db:migrate 时,它不应该在出错的那个上跳闸(因为我们删除了它),然后它应该运行这个,这会删除该列并将其添加回来使用正确的类型。

如果您确实有要保存的数据,则该过程会更加复杂。您的更改方法必须获取每个评论的当前 user_id,然后在我们创建新列时将它们分配给新的 cmets。以下应该有希望工作:

def change
  user_ids = {}
  Comment.find_each{ |c| user_ids[c.id] = c.user_id.to_i } 

  remove_column :comments, :user_id
  add_column :comments, :user_id, :integer
  add_index :comments, :user_id
  Comment.each{ |c| c.update_attribute(:user_id, user_ids[c.id])
end

还要注意命令中migration的名字一般都是CamelCase或者都是snake_case。所以:AddColumnUserIdToCommentsadd_column_user_id_to_comments。像您那样命名可能会导致问题。

** 编辑 **

Modify a Column's Type in sqlite3

SQLite 似乎没有修改/删除列的好方法。我建议:

删除并重新启动 SQLITe 表

删除表,删除原始的 user_id 迁移和新的关于删除旧的 user_id 列的行,然后使用新的迁移创建一个新表。如果您不关心数据,应该可以正常工作

切换到 Postgres,这是 Heroku 使用的数据库。

这可能是个好主意(因为您希望生产数据库和本地数据库的行为相同),但切换到该数据库可能容易出错。

在这里寻找指导——Change from SQLite to PostgreSQL in a fresh Rails project

【讨论】:

  • 我尝试了建议的def更改方法。我不关心数据。这是我现在遇到的错误...173-230-187-53:cp299 louismorin$ rake db:migrate rake aborted! ActiveRecord::DuplicateMigrationNameError: 多个迁移的名称为 AddUserIdToComments 任务:TOP => db:migrate(通过使用 --trace 运行任务查看完整跟踪)
  • 听起来你有两个同名的迁移:)。第二个失败的将不会运行,因此删除它不应该与迁移历史混淆。我只是删除第二个(按时间戳排序),然后重试。
  • 我删除了第二次迁移,现在又回到了和之前一样的错误 ``` 173-230-187-53:cp299 louismorin$ rake db:migrate == 20140910190321 ChangeTypeOfUserIdOnComments: migrating ===================== -- remove_column(:cmets, :user_id) -> 0.0180s -- add_column(:cmets, :user_id, :integer) rake 中止! StandardError:发生错误,此迁移和所有后续迁移已取消:SQLite3::SQLException:重复列名:user_id:ALTER TABLE "cmets" ADD "user_id" integer/Users/louismorin/code/CP299/db/migrate/20140910190321_change_type_of_user_id_on_cmets。 rb:4:..```
  • 更新了我的答案——似乎 SQLite 比我想象的更严格。
  • 嗨,Sasha,我下载了sqlitestudio.pl,然后把桌子放下了。当我查看 cmets 表 Index 和 User_Id 时...运行 rake db:migrate 时出现此错误
猜你喜欢
  • 2012-05-15
  • 2016-08-09
  • 2019-09-17
  • 2015-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-06
  • 2012-11-24
相关资源
最近更新 更多