如何在laravel中删除具有相同列值的重复行?

eyh26e7m  于 2021-06-23  发布在  Mysql
关注(0)|答案(1)|浏览(399)

我正在尝试在laravel中发出artisan命令,删除所有具有相同地址的场地,并保留id号最低的场地(因此首先创建)。
为此,我需要检查3个字段:“street”、“house\u number”、“house\u number\u 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();
}

只有删除不起作用,但也没有给出错误。

2w3kk1z5

2w3kk1z51#

为了能够删除一个项目,雄辩需要知道它的id。如果你确保你的模型的id被查询到,你可以打电话 delete() 没有问题。
但是,在您的查询中,这将不起作用,因为您有一个 GROUP_BY 语句,因此sql不允许您选择 id 列(请参见此处)。
这里最简单的解决方法是利用雄辩的 Collection 类来Map模型,例如:

$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();

注意:最后一个将永久删除您的模型;这对雄辩者不起作用 SoftDeletes 功能。
当然,您也可以编写一个原始查询来完成这一切。

相关问题