【问题标题】:How to get only the second duplicated record in laravel 5.5?如何在 laravel 5.5 中只获取第二条重复记录?
【发布时间】:2020-05-08 05:44:57
【问题描述】:

假设我有一个这样的用户表:

+----+-----------+----------------------+------+
| ID | Name      | Email                | Age  |
+----+-----------+----------------------+------+
| 1  | John      | john.doe1@mail.com   | 24   |
| 2  | Josh      | josh99@mail.com      | 29   |
| 3  | Joseph    | joseph410@mail.com   | 21   |
| 4  | George    | gge.48@mail.com      | 28   |
| 5  | Joseph    | jh.city89@mail.com   | 24   |
| 6  | Kim       | kimsd@mail.com       | 32   |
| 7  | Bob       | bob.s@mail.com       | 38   |
| 8  | Joseph    | psa.jos@mail.com     | 34   |
| 9  | Joseph    | joseph.la@mail.com   | 28   |
| 10 | Jonathan  | jonhan@mail.com      | 22   |
+----+-----------+---------+------------+------+

实际上,数据库包含更多的数据,并且一些数据是重复的,有两条以上的记录。但关键是我只想获取包含“Joseph”名称的重复行的第一行和第二行,我该如何实现呢?到目前为止我的代码...

User::withTrashed()->groupBy('name')->havingRaw('count("name") >= 1')->get();

使用该代码将检索结果:

+----+-----------+----------------------+------+
| ID | Name      | Email                | Age  |
+----+-----------+----------------------+------+
| 1  | John      | john.doe1@mail.com   | 24   |
| 2  | Josh      | josh99@mail.com      | 29   |
| 3  | Joseph    | joseph410@mail.com   | 21   |
| 4  | George    | gge.48@mail.com      | 28   |
| 6  | Kim       | kimsd@mail.com       | 32   |
| 7  | Bob       | bob.s@mail.com       | 38   |
| 10 | Jonathan  | jonhan@mail.com      | 22   |
+----+-----------+---------+------------+------+

我使用此代码尝试获取第二个重复行:

User::withTrashed()->groupBy('name')->havingRaw('count("name") >= 2')->get();

结果还是和上面说的一样:

+----+-----------+----------------------+------+
| ID | Name      | Email                | Age  |
+----+-----------+----------------------+------+
| 1  | John      | john.doe1@mail.com   | 24   |
| 2  | Josh      | josh99@mail.com      | 29   |
| 3  | Joseph    | joseph410@mail.com   | 21   |
| 4  | George    | gge.48@mail.com      | 28   |
| 6  | Kim       | kimsd@mail.com       | 32   |
| 7  | Bob       | bob.s@mail.com       | 38   |
| 10 | Jonathan  | jonhan@mail.com      | 22   |
+----+-----------+---------+------------+------+

我希望结果是获得 ID 为“5”且名称为“Joseph”的记录,如下所示:

    +----+-----------+----------------------+------+
    | ID | Name      | Email                | Age  |
    +----+-----------+----------------------+------+
    | 1  | John      | john.doe1@mail.com   | 24   |
    | 2  | Josh      | josh99@mail.com      | 29   |
    | 4  | George    | gge.48@mail.com      | 28   |
    | 5  | Joseph    | jh.city89@mail.com   | 24   |
    | 6  | Kim       | kimsd@mail.com       | 32   |
    | 7  | Bob       | bob.s@mail.com       | 38   |
    | 10 | Jonathan  | jonhan@mail.com      | 22   |
    +----+-----------+---------+------------+------+

但似乎只检索了第一个重复行,我无法获得第二个重复行,有人可以给我建议吗?

【问题讨论】:

    标签: mysql database laravel laravel-5 eloquent


    【解决方案1】:

    让我们从您的查询开始

    User::withTrashed()->groupBy('name')->havingRaw('count("name") >= 1')->get();
    

    这将显示计数等于或大于 1 的所有行组。这是DISTINCT的描述。

    如果您只想获取重复记录,您应该获取计数大于 1 的组。

    这里要注意的另一件事是,将随机选择一个非聚合列。因为当您获得一个名称并且它是计数时,例如,如果您选择 name,count(name), email(电子邮件不在 group by 子句中 - 未聚合),并且 4 行具有相同的名称。所以你会看到:

    +--------+-------------+-------+
    | Name   | Count(Name) | Email |
    +--------+-------------+-------+
    | Joseph | 4           | X     |
    +--------+-------------+-------+
    

    你期望什么而不是X? 4 封电子邮件中的哪一封?实际上,在 SQLServer 中,禁止选择非聚合列,其他数据库只会给你一个随机的 3 个。 有关详细信息,请参阅此答案,它的解释非常好:Do all columns in a SELECT list have to appear in a GROUP BY clause

    因此,我们将使用 having count(name) > 1 并仅选择聚合列 name

    DB::from('users')->select('name')->groupBy('name')->havingRaw('count("name") > 1')->get();
    

    这应该给你(没有测试过)这个:

    +--------+-------------+
    | name   | Count(name) |
    +--------+-------------+
    | Joseph | 4           |
    +--------+-------------+
    

    这将为您提供具有 2 个或更多实例的所有名称。您可以确定have子句中的重复数。例如having count(name) = 3 会给你所有的名字恰好有 3 个重复。

    那么如何获得第二个副本?我有一个问题:

    第一个(原始)副本是什么?是最古老的created_at 还是最古老的updated_at?或者可能是其他一些情况?因此,您应该使用order by 子句进行另一个查询,以便按照您最方便的顺序为您提供重复项。例如:

    select * from `users` where `name` in  (select `name` from users group by `name` having count(`name`) > 1) order by `id` asc
    

    这将给出:

    +----+-----------+----------------------+------+
    | ID | Name      | Email                | Age  |
    +----+-----------+----------------------+------+
    | 3  | Joseph    | joseph410@mail.com   | 21   |
    | 5  | Joseph    | jh.city89@mail.com   | 24   |
    | 8  | Joseph    | psa.jos@mail.com     | 34   |
    | 9  | Joseph    | joseph.la@mail.com   | 28   |
    +----+-----------+---------+------------+------+
    

    【讨论】:

    • 非常感谢您的帮助,您的详细回答尤其是查询解决了问题!
    猜你喜欢
    • 2015-08-13
    • 2014-10-23
    • 2018-08-02
    • 1970-01-01
    • 2023-03-15
    • 2018-07-19
    • 2018-08-31
    • 2022-01-14
    • 2011-08-27
    相关资源
    最近更新 更多