我正试图在Laravel中执行一个工匠命令,以删除所有具有相同地址的场所,并保留具有最低ID号(因此是第一个创建)的场所。
为此,我需要检查3个字段:“街道”,“ house_number”,“ house_number_addition”
这是我的目标:
$venues = Venue::select('street', 'house_number', 'house_number_addition', DB::raw('COUNT(*) as count'))
->groupBy('street', 'house_number', 'house_number_addition')
->having('count', '>', 1)
->get();
foreach ($venues as $venue) {
$this->comment("Removing venue: {$venue->street} {$venue->house_number} {$venue->house_number_addition}");
$venue->delete();
}
仅删除操作无效,但也没有出现错误。
答案 0 :(得分:4)
要能够删除某项,Eloquent需要知道它的ID。如果您确定要查询模型的ID,则可以毫无问题地致电delete()
。
但是,由于您有一个GROUP_BY
语句,因此在您的查询中将不起作用,因此SQL不允许您选择id
列(see here)。 / p>
这里最简单的解决方案是利用Eloquent的Collection
类来映射模型,例如:
$uniqueAddresses = [];
Venue::all()
->filter(function(Venue $venue) use (&$uniqueAddresses) {
$address = sprintf("%s.%s.%s",
$venue->street,
$venue->house_number,
$venue->house_number_addition);
if (in_array($address, $uniqueAddresses)) {
// address is a duplicate
return $venue;
}
$uniqueAddresses[] = $address;
})->map(function(Venue $venue) {
$venue->delete();
});
或者,使删除查询更有效率(取决于数据集的大小):
$uniqueAddresses = [];
$duplicates = [];
Venue::all()
->map(function(Venue $venue) use (&$uniqueAddresses, &$duplicates) {
$address = sprintf("%s.%s.%s",
$venue->street,
$venue->house_number,
$venue->house_number_addition);
if (in_array($address, $uniqueAddresses)) {
// address is a duplicate
$duplicates[] = $venue->id;
} else {
$uniqueAddresses[] = $address;
}
});
DB::table('venues')->whereIn('id', $duplicates)->delete();
注意:最后一个 将永久删除您的模型;它不适用于Eloquent的
SoftDeletes
功能。
您当然也可以编写一个原始查询来完成所有这一切。