是否可以根据 Laravel 的 ORM 中的多个列删除重复项?

Posted

技术标签:

【中文标题】是否可以根据 Laravel 的 ORM 中的多个列删除重复项?【英文标题】:Is it possible to remove duplicates based on multiple columns in Laravel's ORM? 【发布时间】:2022-01-05 16:58:44 【问题描述】:

用户可以重新提交比赛结果,它会更新记分板上的结果,但是,它还会为“何时返回”功能创建结果保存,以便能够查看以前的结果以查看改进分数。

我遇到的问题是某些月份存在重复条目,数据库中唯一更改的是主键idcreated_atupdated_at。如果列值:discipline_n wheren is onesix 与任何其他列值都相同,则不应查询,即:

id 1                                     id 2
username foo                             username foo
discipline_one 4                         discipline_one 4
discipline_two 5                         discipline_two 5
discipline_three 8                       discipline_three 8
discipline_four 9                        discipline_four 9
discipline_five 4                        discipline_five 4
discipline_six 6                         discipline_six 6
created_at yesterday for example         created_at today for example
updated_at yesterday for example         updated_at today for example

应该被认为是重复的,因此从结果中删除。我尝试使用 Laravel 的 ORM 中内置的 distinct() 函数,但我仍然得到重复。这可以用 SQL 来完成吗?我的预期输出是:

id 2
username foo
discipline_one 4
...

其中id 1 被忽略为重复项。我试过了:

$waybackWhen = \App\Models\ResultSave::where('username', $result->username)
    ->distinct([
        'discipline_one',
        'discipline_two',
        'discipline_three',
        'discipline_four',
        'discipline_five',
        'discipline_six',
    ])
    ->get();

【问题讨论】:

【参考方案1】:

根据我前段时间提出的一个问题,我对它进行了一些尝试。

WITH cte AS (
    SELECT *, ROW_NUMBER() OVER
    (PARTITION BY username, discipline_one, discipline_two, discipline_three,
     discipline_four, discipline_five, discipline_six ORDER BY id DESC) rn
    FROM results
)

SELECT id, username, discipline_one, discipline_two, discipline_three,
     discipline_four, discipline_five, discipline_six, created_at, updated_at
FROM cte
WHERE rn = 1

致谢:@tim-biegeleisen mysql : Find duplicate records but EXCLUDE the first one from the list

之前

id username discipline_one discipline_two discipline_three discipline_four discipline_five discipline_six created_at updated_at
1 qivr 489 23 1 2 89 34 2021-11-21 17:49:28 2021-11-25 18:40:26
7 foo 4 5 8 9 4 6 2021-11-01 19:45:01 2021-11-01 19:45:42
8 foo 4 5 8 9 4 6 2021-11-02 19:45:15 2021-11-02 19:45:46
9 foo 4 5 8 9 4 6 2021-11-03 19:45:20 2021-11-03 19:45:50

之后

id username discipline_one discipline_two discipline_three discipline_four discipline_five discipline_six created_at updated_at
1 qivr 489 23 1 2 89 34 2021-11-21 17:49:28 2021-11-25 18:40:26
9 foo 4 5 8 9 4 6 2021-11-03 19:45:20 2021-11-03 19:45:50

Laravel


    public static function waybackWhen($result)
    
        $username = $result->username;

        config()->set('database.connections.mysql.strict', false);
        DB::reconnect(); // Important as the existing connection if any would be in strict mode.

        $resultSet = DB::select("
            WITH cte AS (
                SELECT *, ROW_NUMBER() OVER
                (PARTITION BY username, discipline_one, discipline_two, discipline_three,
                 discipline_four, discipline_five, discipline_six ORDER BY id DESC) rn
                FROM results
            )
            
            SELECT id, username, discipline_one, discipline_two, discipline_three,
                 discipline_four, discipline_five, discipline_six, created_at, updated_at
            FROM cte
            WHERE rn = 1 AND username = ? 
       ", [ $username ]);

        // Now changing back the strict ON.
        config()->set('database.connections.mysql.strict', true);
        DB::reconnect();

        return $resultSet;

    

输出

=> [
     #3409
       +"id": 9,
       +"username": "foo",
       +"discipline_one": "4",
       +"discipline_two": "5",
       +"discipline_three": "8",
       +"discipline_four": "9",
       +"discipline_five": "4",
       +"discipline_six": "6",
       +"created_at": "2021-11-03 19:45:20",
       +"updated_at": "2021-11-03 19:45:50",
     ,
   ]

【讨论】:

非常感谢,非常感谢您也将您的问题联系起来。这是接近它的好方法!虽然,我怀疑这里有一个没有转义 $username 内容的 SQLi,所以我现在将研究如何在 Laravel 中使用 RAW SQL 查询同时使用准备好的语句。 对于未来的观众,这可以像 PDO 中的正常情况一样在by binding the parameters 完成 @Jaquarh ,也感谢您提供参数绑定建议。我已经相应地重构了我的答案。

以上是关于是否可以根据 Laravel 的 ORM 中的多个列删除重复项?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Eloquent ORM 事务

是否可以在 laravel ORM 的增量中添加 tinyInteger 或 smallInteger?

Laravel Eloquent ORM字段处理

是否有一个带有/ORM(Laravel、Cake、Codeigniter)的 PHP 框架,我们可以在其中覆盖数据交互以从 rest api 中获取数据?

如何在 laravel 5.4 orm 中执行多个 has() /orHas()

如何在 Laravel 中为 ORM 急切加载添加多个键约束?