Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 4 用于标识孤立子记录的ActiveRecord查询_Ruby On Rails 4_Activerecord_Query String_Postgresql 9.3 - Fatal编程技术网

Ruby on rails 4 用于标识孤立子记录的ActiveRecord查询

Ruby on rails 4 用于标识孤立子记录的ActiveRecord查询,ruby-on-rails-4,activerecord,query-string,postgresql-9.3,Ruby On Rails 4,Activerecord,Query String,Postgresql 9.3,我有Post和用户模型。每个帖子都属于一个用户。但是,在数据库导入过程中,在某些帖子上输入了一些错误的用户ID。如果要获取用户ID不指向任何用户的帖子,查询将是什么?谢谢。我不认为你可以用straight AR实现这一点,但用一点Ruby就可以很容易地修复: Post.find_each { |p| p.delete if p.user.nil? } 编辑:忘记。all不会返回ActiveRecord::Relation我将执行以下操作,这将导致一个SELECT和一个DELETE语句(总共2个

我有Post和用户模型。每个帖子都属于一个用户。但是,在数据库导入过程中,在某些帖子上输入了一些错误的用户ID。如果要获取用户ID不指向任何用户的帖子,查询将是什么?谢谢。

我不认为你可以用straight AR实现这一点,但用一点Ruby就可以很容易地修复:

Post.find_each { |p| p.delete if p.user.nil? }

编辑:忘记
。all
不会返回
ActiveRecord::Relation

我将执行以下操作,这将导致一个
SELECT
和一个
DELETE
语句(总共2个查询)


谢谢你们两位。我的解决方案与曼纽尔的类似

all_user_ids = User.all.pluck(:id)
unwanted_posts = Post.where.not(:user_id => all_user_ids)
然后我可以销毁所有不需要的帖子。当然,另一种解决方案也会奏效

桑杰

所有建议的解决方案都适用于小型表,但根据所涉及表的大小、可用内存量和处理能力,出于性能原因,您可能希望使用左外部联接,如下所示:

Post.joins("LEFT OUTER JOIN users ON posts.user_id = user.id")
    .where("user.id IS NULL")
Post.left_outer_joins(:user).where(users: {id: nil}).delete_all
在Rails 5中,有一个


正如前面提到的@user2553863一样,Rails 5增加了对的支持,这意味着您现在可以高效地完成这项工作,而无需编写任何类似以下的SQL:

Post.joins("LEFT OUTER JOIN users ON posts.user_id = user.id")
    .where("user.id IS NULL")
Post.left_outer_joins(:user).where(users: {id: nil}).delete_all

这将找到任何孤立的帖子(没有用户的帖子)并删除它们。这里,
user
是关联名称,
users
是联接表的名称。您不必启动额外的
选择
来查询所有用户ID,当您有许多用户时,这些ID可能会中断。

注意:以下答案对Rails 5.0有效

这些答案中的许多对于一些记录或小表都适用,但对于拥有大量孤立记录或处理大表来说,它们的扩展性并不好

例如,处理两个较大的表,其中
ModelOne
有707891条孤立记录:

irb(main):032:0> ModelOne.count
=> 2,265,216
irb(main):033:0> ModelTwo.count
=> 5,109,186
尝试执行
不在
中的查询将失败,因为该查询太大:

irb(main):029:0> ModelOne.where.not(model_two_id: ModelTwo.pluck(:id))
ActiveRecord::StatementInvalid (Mysql2::Error: MySQL server has gone away: SELECT `model_ones`.* FROM `model_ones` WHERE (`model_ones`.`model_two_id` NOT IN (12068663, 12076647, 12076648, 12082392, 12082393, 12082394, <repeat for the other 5 million ModelTwo records>))
但是将
.delete\u all
链接到末尾(
ModelOne.left\u outer\u连接(:model\u two)。其中(model\u twos:{id:nil})。delete\u all
)生成:

DELETE FROM `model_ones` WHERE `model_twos`.`id` IS NULL
SELECT `model_ones`.* FROM `model_ones`
WHERE (
  NOT (
    EXISTS (
      SELECT `model_twos`.* FROM `model_twos` WHERE (model_twos.id = model_ones.model_two_id)
    )
  )
)
这将抛出一个错误

我发现删除孤立记录最有效的方法来自并使用SQL
EXISTS
和嵌套查询来高效地查找和删除孤立记录

ModelOne.where.not(
  ModelTwo.where('model_twos.id = model_ones.model_two_id').exists
)
由此产生:

DELETE FROM `model_ones` WHERE `model_twos`.`id` IS NULL
SELECT `model_ones`.* FROM `model_ones`
WHERE (
  NOT (
    EXISTS (
      SELECT `model_twos`.* FROM `model_twos` WHERE (model_twos.id = model_ones.model_two_id)
    )
  )
)
使用此查询加载707891孤立记录只需不到一分钟的时间:

irb(main):040:0> Benchmark.measure { ModelOne.where.not(ModelTwo.where('model_twos.id = model_ones.model_two_id').exists).load }
=> #<Benchmark::Tms:0x0000563cfa227580 @label="", @real=59.61208474007435, @cstime=0.0, @cutime=0.0, @stime=0.23068100000000014, @utime=49.025859000000025, @total=49.25654000000002>
生成SQL:

  DELETE FROM `model_ones` WHERE (NOT (EXISTS (SELECT `model_twos`.* FROM `model_twos` WHERE (model_twos.id = model_ones.model_two_id))))

RAILS 6.1+

您可以使用“missing”方法获取孤立记录。乙二醇

Class User
end

Class Post
  belongs_to :user
end
下面是使用missing方法的时间

Post.where.missing(:user)

这将获取所有具有用户id但相应用户被删除的Post记录。

这不是两次选择吗?一个用于Pull,一个用于“where”语句?发现了一个有趣的警告——只有存在一些非孤儿记录时,这才有效。如果它们都是孤立项,ActiveRecord最终会使用子句
posts.user\u id NOT IN(NULL)
执行查询,即使存在记录,该子句实际上也不会返回任何内容。下面的加入推荐@user2553863状态是最可靠的。谢谢。这将解决阵列可能导致的内存问题。谢谢!好提示!