简短版本:我需要使用自定义内部联接来查找一个表中的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而没有任何更改。
很抱歉这个漫长而曲折的问题。有人有什么建议吗?谢谢!
答案 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
似乎有效!