Rails INNER JOIN期待字段" id"那还不存在

时间:2015-01-12 21:36:13

标签: sql ruby-on-rails rails-activerecord

简短版本:我需要使用自定义内部联接来查找一个表中的id,其中两个字段在Rails中的两个表中都匹配,但Rails内部联接会假设关于我不知道如何解决的关系。

长版本:我接管了一个有非规范化数据库的Rails项目。我将一些信息提取到一个新表中,现在我需要遍历每个条目并将一个外键放在原始表上,但是我无法提供正确的ActiveRecord查询来获取信息。

在此方案中,集合属于存储库,存储库可能包含许多集合。

项目最初将所有集合和存储库存储在同一个表中,如果它是一个存储库,则集合名称为NULL,如果它是集合,则包含存储库名称和集合名称。我创建了一个迁移,它获取了所有唯一的存储库名称并将它们放在存储库表中。现在我需要做的是返回集合表并根据字符串repname从匹配的存储库中添加id。

我在SQL中有一个查询来提取正确的数据:

ActiveRecord::Base.connection.execute("SELECT r.id, r.repname FROM collections c, repositories r WHERE c.repname = r.repname")

我无法与该对象进行交互,但是(对于#Mysql2 :: Result ...会出现“undefined method'last''之类的错误),我希望我知道所有内容都已正确设置Rails模型。

当我尝试这个时,我收到一个错误:

Repository.joins(:collections).where("collections.repname = repositories.repname")
Repository Load (1.0ms)  SELECT `repositories`.* FROM `repositories` INNER JOIN `collections` 
ON `collections`.`repository_id` = `repositories`.`id` WHERE (collections.repname = repositories.repname)

Mysql2::Error: Unknown column 'collections.repository_id' in 'on clause': SELECT `repositories`.* FROM `repositories` INNER JOIN `collections` ON `collections`.`repository_id` = `repositories`.`id` WHERE (collections.repname = repositories.repname)
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'collections.repository_id' in 'on clause': SELECT `repositories`.* FROM `repositories` INNER JOIN `collections` ON `collections`.`repository_id` = `repositories`.`id` WHERE (collections.repname = repositories.repname)

我是Rails和SQL的新手,所以我认为我的问题实际上可能在于我如何设置模型。我正在使用数据库的现有命名约定......也许我应该切换到Rails repository_id约定,而不是?

class Collection < ActiveRecord::Base
  has_many :archive_object_collections, :foreign_key => :collid, :primary_key => :collid
  has_many :archive_object, :through => :archive_object_collections
  belongs_to :repository, :foreign_key => "repid"
end

class Repository < ActiveRecord::Base
  has_many :collections
end

我担心切换到repository_id不能解决问题,因为在集合表上没有任何类型的id。这就是我需要运行此查询的原因,因此我可以在集合表中找到并插入该信息作为外键。我已经尝试了内部联接查询而没有收集类中的foreign_key而没有任何更改。

很抱歉这个漫长而曲折的问题。有人有什么建议吗?谢谢!

2 个答案:

答案 0 :(得分:1)

我认为您应该在存储库模型中定义foreign_key

class Repository < ActiveRecord::Base
  has_many :collections, :primay_key => 'somekey',  :foreign_key => 'repid'
end

然后您可以运行一个简单的连接查询来根据您的查询获取结果。

Repository.select('repositories.*, collections.*').where("repositories.col1 = ? AND collections.col2 = ?", val1, val2)

否则,如果你想摆脱这些键定义,那么最好开始使用rails约定。将外键定义为 model_id 。在这种情况下,您不必定义键名。

答案 1 :(得分:0)

我决定遍历集合和存储库表并手动匹配它。这就是我最终做的事情:

class AddForeignKeyToColl < ActiveRecord::Migration
  def up
    # Add a repid to the collections
    add_column :collections, :repository_id, :integer

    # Need to go through all of the repositories
    # and match their name against the repname of the collections
    # Then, if they match, add the repository id to the collection as repid
    repos = Repository.all
    colls = Collection.all
    repos.each do |repo|
      rname = repo.repname
      colls.each do |coll|
        if coll.repname == rname
          coll.update_attributes(:repository_id => repo.id)
        end
      end
    end
  end

  def down
    raise ActiveRecord::IrreversibleMigration
  end
end

似乎有效!