【问题标题】:How to get distinct values for non-key column fields in Laravel?如何在 Laravel 中获取非键列字段的不同值?
【发布时间】:2014-10-03 10:16:45
【问题描述】:

这可能很容易,但不知道怎么做。

我有一个表,可以为特定的非键列字段包含重复值。如何使用 Query Builder 或 Eloquent 编写 SQL 查询,以获取该列具有不同值的行?

请注意,我不是仅获取该列,它与其他列值结合使用,因此distinct() 可能无法真正起作用。所以这个问题基本上可以是在distinct() 不接受任何参数的情况下,如何在查询中指定我想要区分的列?

【问题讨论】:

    标签: laravel eloquent builder


    【解决方案1】:

    您应该使用groupby。在查询生成器中,您可以这样做:

    $users = DB::table('users')
                ->select('id','name', 'email')
                ->groupBy('name')
                ->get();
    

    【讨论】:

    • 我有一个表“消息”(用于聊天),我想获取经过身份验证的用户从每个对话中收到的最新消息。使用 groupBy 我只能收到一条消息,但我收到了第一条消息,我需要最后一条消息。似乎 orderBy 不起作用。
    • 如果您不想应用任何数学运算,例如 SUM、AVG、MAX 等“分组依据”不是正确答案(您可以使用它,但您不应该使用它)。你应该使用不同的。在 MySQL 中,您可以将 DISTINCT 用于列并向结果集中添加更多列:“SELECT DISTINCT name, id, email FROM users”。使用 eloquent 你可以使用 $this->select(['name', 'id', 'email'])->distinct()->get();
    • 当我添加 where() 时它会中断,我该如何解决这个问题?
    • 当我使用它时,它显示 'id' 和 'email' 不在 groupBy() 中,我需要使用 groupBy('id','name', 'email')。哪个没用。
    • 注意事项:group bydistinct 不同。 group by 将改变 SQL 查询中的聚合函数(如 count())的行为。 distinct 不会改变这些函数的行为,所以你会得到不同的结果,这取决于你使用哪一个。
    【解决方案2】:

    在 Eloquent 中你也可以这样查询:

    $users = User::select('name')->distinct()->get();

    【讨论】:

    • 问题具体问Note that I am not fetching that column only, it is in conjunction with other column values
    • @Hirnhamster:Okkei。但是,这个答案对于路过的其他人仍然有用...
    • 对我没用,我专门看 OP 是什么。不容易找到。
    • $users = User::select('column1', 'column2', 'column3')->distinct()->get();
    • 如果你想和chunk一起使用,你还需要->orderBy('name')
    【解决方案3】:

    在 eloquent 中你可以使用这个

    $users = User::select('name')->groupBy('name')->get()->toArray() ;
    

    groupBy 实际上是获取不同的值,实际上 groupBy 会对相同的值进行分类,以便我们可以对它们使用聚合函数。但在这种情况下,我们没有聚合函数,我们只是选择会导致结果具有不同值的值

    【讨论】:

    • 这是如何工作的? groupBy 实际上是在获取不同的用户名吗?您能否再解释一下这如何回答 op 的问题?
    • 是的 groupBy 实际上是在获取不同的值,实际上 groupBy 会对相同的值进行分类,以便我们可以对它们使用聚合函数。但在这种情况下,我们没有聚合函数,我们只是选择会导致结果具有不同值的值。
    • 我明白了.. 那么,这个答案与 Marcin 的答案有何不同?有不同的答案是可以的,只要你能解释它有什么不同以及它解决了什么缺陷:) 不要在 cmets 中回答,请直接用相关信息编辑你的问题。
    • 结果是一样的,这取决于你的项目是使用ORM还是使用查询生成器,如果你使用其中之一,那么最好坚持使用那个。这就是为什么我以不同的方式回答你的问题。
    • 好吧,我有这个问题,如果你现在想使用in_array() 函数检查一个项目是否存在,它永远不会工作。为了解决这个问题,我尝试了->lists()(版本 5.2)。所以,$users = User::select('name')->groupBy('name')->lists('name'); 对 php 的 in_array() 工作得很好;
    【解决方案4】:

    虽然我回答这个问题迟了,但使用 Eloquent 获取不同记录的更好方法是

    $user_names = User::distinct()->get(['name']);
    

    【讨论】:

    • 好的,您通过向我们展示了也可以将字段名称的参数传递给get() 方法(我也测试过first() 方法)来增加价值,这是相当于使用select() 方法,如这里的几个答案所示。虽然不知何故groupBy 似乎仍然得分最高。但是,如果这是我选择的唯一列,这将是真正不同的。
    • 性能方面,distinct 将超过 groupBy,因为记录将首先在 SQL 引擎中被选择,这与 Group By 引擎不同,引擎首先选择所有记录,然后再分组。
    • $user_names = User::distinct()->count(['name']); 也可以
    【解决方案5】:

    如果数据库规则不允许任何选择字段位于聚合函数之外,则分组依据将不起作用。请改用laravel collections

    $users = DB::table('users')
            ->select('id','name', 'email')
            ->get();
    
    foreach($users->unique('name') as $user){
      //....
    }
    

    有人指出,这对于大型集合的性能可能不是很好。我建议在集合中添加一个密钥。使用的方法称为keyBy。这是简单的方法。

         $users = DB::table('users')
            ->select('id','name', 'email')
            ->get()
            ->keyBy('name');
    

    keyBy 还允许您为更复杂的事情添加回调函数...

         $users = DB::table('users')
            ->select('id','name', 'email')
            ->get()
            ->keyBy(function($user){
                  return $user->name . '-' . $user->id;
             });
    

    如果您必须对大型集合进行迭代,则为其添加一个键可以解决性能问题。

    【讨论】:

    • 你是对的,这正是我所面临的问题......但是等到执行查询并执行集合中的操作也不理想。特别是如果您依赖分页,您的操作将在分页计算之后,并且每页的项目将是错误的。此外,数据库更适合对大数据块进行操作,而不是在代码中检索和处理它。对于小数据块,这将不是问题
    • 你说得很好。这种方法在大型集合上的性能可能不是很好,而且这不适用于分页。我认为有比我所拥有的更好的答案。
    【解决方案6】:

    **

    为 Laravel 5.8 测试

    **

    由于您想从表中获取所有列,您可以收集所有数据,然后使用名为 Unique 的 Collections 函数对其进行过滤

    // Get all users with unique name
    User::all()->unique('name')
    

    // Get all & latest users with unique name 
    User::latest()->get()->unique('name')
    

    更多信息可以查看Laravel Collection Documentations

    编辑:您可能会遇到性能问题,通过使用 Unique() 您将首先从 User 表中获取所有数据,然后 Laravel 将对其进行过滤。 如果您有大量用户数据,这种方式并不好。您可以使用查询生成器并调用您想要使用的每个字段,例如:

    User::select('username','email','name')->distinct('name')->get();
    

    【讨论】:

    • 这效率不高,因为您首先从 db 获取所有数据
    • 这就是为什么它被称为过滤,您可以使用 distinct() 作为查询构建器,但您无法获取其他字段(无论如何您仍然可以通过 select 调用每个字段)。通过使用 unique() 是获取所有字段而不调用每个字段的唯一方法(尽管我们知道这可能会导致性能问题)。
    【解决方案7】:

    请注意,上面使用的 groupBy 不适用于 postgres。

    使用distinct 可能是更好的选择 - 例如 $users = User::query()->distinct()->get();

    如果您使用query,您可以按要求选择所有列。

    【讨论】:

      【解决方案8】:

      $users = User::select('column1', 'column2', 'column3')->distinct()->get(); 检索表中不同行的所有三个列。您可以添加任意数量的列。

      【讨论】:

        【解决方案9】:

        我发现这种方法(对我来说)工作得很好,可以生成唯一值的平面数组:

        $uniqueNames = User::select('name')->distinct()->pluck('name')->toArray();
        

        如果您在此查询构建器上运行 ->toSql(),您将看到它生成如下查询:

        select distinct `name` from `users`
        

        ->pluck() 由Illumination\collection lib 处理(不是通过sql 查询)。

        【讨论】:

          【解决方案10】:

          在尝试填充用户与其他用户拥有的所有唯一线程的列表时,我遇到了同样的问题。这对我有用

          Message::where('from_user', $user->id)
                  ->select(['from_user', 'to_user'])
                  ->selectRaw('MAX(created_at) AS last_date')
                  ->groupBy(['from_user', 'to_user'])
                  ->orderBy('last_date', 'DESC')
                  ->get()
          

          【讨论】:

            【解决方案11】:
            // Get unique value for table 'add_new_videos' column name 'project_id'
            $project_id = DB::table('add_new_videos')->distinct()->get(['project_id']);
            

            【讨论】:

              【解决方案12】:

              对于那些喜欢我犯同样错误的人。这是详细的答案 在 Laravel 5.7 中测试

              A.数据库中的记录

              UserFile::orderBy('created_at','desc')->get()->toArray();

              Array
              (
                  [0] => Array
                      (
                          [id] => 2073
                          [type] => 'DL'
                          [url] => 'https://i.picsum.photos/12/884/200/300.jpg'
                          [created_at] => 2020-08-05 17:16:48
                          [updated_at] => 2020-08-06 18:08:38
                      )
              
                  [1] => Array
                      (
                          [id] => 2074
                          [type] => 'PROFILE'
                          [url] => 'https://i.picsum.photos/13/884/200/300.jpg'
                          [created_at] => 2020-08-05 17:20:06
                          [updated_at] => 2020-08-06 18:08:38
                      )
              
                  [2] => Array
                      (
                          [id] => 2076
                          [type] => 'PROFILE'
                          [url] => 'https://i.picsum.photos/13/884/200/300.jpg'
                          [created_at] => 2020-08-05 17:22:01
                          [updated_at] => 2020-08-06 18:08:38
                      )
              
                  [3] => Array
                      (
                          [id] => 2086
                          [type] => 'PROFILE'
                          [url] => 'https://i.picsum.photos/13/884/200/300.jpg'
                          [created_at] => 2020-08-05 19:22:41
                          [updated_at] => 2020-08-06 18:08:38
                      )
              )
              

              B.期望的分组结果

              UserFile::select('type','url','updated_at)->distinct('type')->get()->toArray();

              Array
              (
                  [0] => Array
                      (
                          [type] => 'DL'
                          [url] => 'https://i.picsum.photos/12/884/200/300.jpg'
                          [updated_at] => 2020-08-06 18:08:38 
                      )
              
                  [1] => Array
                      (
                          [type] => 'PROFILE'
                          [url] => 'https://i.picsum.photos/13/884/200/300.jpg'
                          [updated_at] => 2020-08-06 18:08:38
                      )
              )
              

              所以只传递"select()" 中的那些列,它们的值是相同的。 例如:'type','url'。您可以添加更多列,前提是它们具有相同的值,例如 'updated_at'

              如果您尝试在"select()" 中传递"created_at""id",那么您将获得与A 相同的记录。 因为它们对于 DB 中的每一行都是不同的。

              【讨论】:

                【解决方案13】:
                $users = Users::all()->unique('name');
                

                【讨论】:

                • 请解释您的代码 sn-p 如何解决 OP 的问题。
                【解决方案14】:

                以下是我测试过的 3 种方法,它们会给出相同的结果:

                User::distinct()->get(['name'])->pluck('name');
                
                User::select('name')->distinct()->pluck('name')->all();
                
                DB::table('users')->select('name')->groupBy('name')->get()->pluck('name')->all();
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2023-04-08
                  • 2021-10-25
                  • 2021-02-10
                  • 2019-04-06
                  • 2019-05-11
                  • 2014-05-04
                  • 1970-01-01
                  相关资源
                  最近更新 更多