我有Post和User模型。每个帖子都属于一个用户。但是,在数据库导入期间,某些帖子上输入了一些错误的user_id。获取user_ids不引用任何用户的帖子的查询是什么?感谢。
答案 0 :(得分:4)
桑杰,
所有提出的解决方案适用于小型表,但是根据所涉及的表的大小,以及可用的内存量和处理能力,出于性能原因,您可能希望使用LEFT OUTER JOIN,如下所示:
var app = angular.module('myApp', []);
app.controller('testCtrl', function($scope) {
$scope.company = [{id:1, name:"Sole Trader", rating:4},{id:2, name:"Pvt Ltd", rating:3},{id:3, name:"LLC", rating:5}];
$scope.Newrat = [];
$scope.addRatingbyId = function(pushdata){
if($scope.Newrat.length != 0){
angular.forEach($scope.Newrat, function(value, index){
if(value.id == pushdata.id){
$scope.Newrat[index].rating = pushdata.rating;
}else{
$scope.Newrat.push(pushdata);
}
});
}else{
$scope.Newrat.push(pushdata);
}
}
$scope.sendRating= function(){
//send $scope.Newrat
console.log($scope.Newrat);
}
});
在Rails 5中,有support for LEFT OUTER JOIN in ActiveRecord。
此致
答案 1 :(得分:4)
正如@ user2553863已经提到的,Rails 5添加了对left_outer_joins
的支持,这意味着您现在可以以有效的方式执行此操作,而无需编写任何类似的SQL:
Post.left_outer_joins(:user).where(users: {id: nil}).delete_all
这将找到任何孤立的帖子(没有用户的帖子)并删除它们。这里,user
是关联名称,users
是连接表的名称。您不必再触发其他SELECT
来查询所有用户ID,这可能会在您拥有多个用户时中断。
答案 2 :(得分:3)
我会执行以下操作,这将导致一个SELECT
和一个DELETE
语句(总共2个查询)
Post.where('`posts`.`user_id` NOT IN (?)', User.pluck(:id)).delete_all
答案 3 :(得分:2)
我认为你不能用直接的AR做到这一点,但用一点Ruby来修复它是相当容易的:
Post.find_each { |p| p.delete if p.user.nil? }
编辑:忘了.all
没有返回ActiveRecord::Relation
答案 4 :(得分:2)
感谢你们两位。我的解决方案类似于Manuel的
all_user_ids = User.all.pluck(:id)
unwanted_posts = Post.where.not(:user_id => all_user_ids)
然后我可以销毁所有的unwanted_posts。当然,其他解决方案也可以。
答案 5 :(得分:2)
注意:以下答案对Rails 5.0有效
这些答案中的许多对于一些记录或在小表上都能很好地工作,但对于拥有大量孤立记录或在处理大表时根本无法很好地扩展。
例如,处理两个较大的表,其中ModelOne
具有707,891个孤立记录:
irb(main):032:0> ModelOne.count
=> 2,265,216
irb(main):033:0> ModelTwo.count
=> 5,109,186
尝试使用NOT IN
执行查询会失败,因为它太大:
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_all
的查询上调用left_outer_joins
并没有达到预期的效果。
这是为ModelOne.left_outer_joins(:model_two).where(model_twos: {id: nil})
生成的SQL Rails:
SELECT `model_ones`.* FROM `model_ones`
LEFT OUTER JOIN `model_twos` ON `model_twos`.`id` = `model_ones`.`model_two_id`
WHERE `model_twos`.`id` IS NULL
但是将.delete_all
链接到末尾(ModelOne.left_outer_joins(:model_two).where(model_twos: {id: nil}).delete_all
)会生成:
DELETE FROM `model_ones` WHERE `model_twos`.`id` IS NULL
这将引发错误。
我发现最有效的删除孤立记录的方法来自this answer,它使用SQL EXISTS
和嵌套查询来有效地查找和删除孤立记录。
ModelOne.where.not(
ModelTwo.where('model_twos.id = model_ones.model_two_id').exists
)
哪个生成:
SELECT `model_ones`.* FROM `model_ones`
WHERE (
NOT (
EXISTS (
SELECT `model_twos`.* FROM `model_twos` WHERE (model_twos.id = model_ones.model_two_id)
)
)
)
使用此查询加载707,891个孤立记录需要不到一分钟的时间:
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>
将.delete_all
链接到该查询将按预期工作,并删除所有孤立记录
ModelOne.where.not(ModelTwo.where('model_twos.id = model_ones.model_two_id').exists).delete_all
生成SQL:
DELETE FROM `model_ones` WHERE (NOT (EXISTS (SELECT `model_twos`.* FROM `model_twos` WHERE (model_twos.id = model_ones.model_two_id))))
答案 6 :(得分:0)
铁路6.1 +
您可以使用'missing'方法来获取孤立的记录。例如
Class User
end
Class Post
belongs_to :user
end
这是使用缺少方法的时候
Post.where.missing(:user)
这将获取所有具有user_id但已删除相应用户的Post记录。