【发布时间】:2014-10-03 10:16:45
【问题描述】:
这可能很容易,但不知道怎么做。
我有一个表,可以为特定的非键列字段包含重复值。如何使用 Query Builder 或 Eloquent 编写 SQL 查询,以获取该列具有不同值的行?
请注意,我不是仅获取该列,它与其他列值结合使用,因此distinct() 可能无法真正起作用。所以这个问题基本上可以是在distinct() 不接受任何参数的情况下,如何在查询中指定我想要区分的列?
【问题讨论】:
这可能很容易,但不知道怎么做。
我有一个表,可以为特定的非键列字段包含重复值。如何使用 Query Builder 或 Eloquent 编写 SQL 查询,以获取该列具有不同值的行?
请注意,我不是仅获取该列,它与其他列值结合使用,因此distinct() 可能无法真正起作用。所以这个问题基本上可以是在distinct() 不接受任何参数的情况下,如何在查询中指定我想要区分的列?
【问题讨论】:
您应该使用groupby。在查询生成器中,您可以这样做:
$users = DB::table('users')
->select('id','name', 'email')
->groupBy('name')
->get();
【讨论】:
where() 时它会中断,我该如何解决这个问题?
group by 与 distinct 不同。 group by 将改变 SQL 查询中的聚合函数(如 count())的行为。 distinct 不会改变这些函数的行为,所以你会得到不同的结果,这取决于你使用哪一个。
在 Eloquent 中你也可以这样查询:
$users = User::select('name')->distinct()->get();
【讨论】:
Note that I am not fetching that column only, it is in conjunction with other column values
$users = User::select('column1', 'column2', 'column3')->distinct()->get();
chunk一起使用,你还需要->orderBy('name')。
在 eloquent 中你可以使用这个
$users = User::select('name')->groupBy('name')->get()->toArray() ;
groupBy 实际上是获取不同的值,实际上 groupBy 会对相同的值进行分类,以便我们可以对它们使用聚合函数。但在这种情况下,我们没有聚合函数,我们只是选择会导致结果具有不同值的值
【讨论】:
in_array() 函数检查一个项目是否存在,它永远不会工作。为了解决这个问题,我尝试了->lists()(版本 5.2)。所以,$users = User::select('name')->groupBy('name')->lists('name'); 对 php 的 in_array() 工作得很好;
虽然我回答这个问题迟了,但使用 Eloquent 获取不同记录的更好方法是
$user_names = User::distinct()->get(['name']);
【讨论】:
get() 方法(我也测试过first() 方法)来增加价值,这是相当于使用select() 方法,如这里的几个答案所示。虽然不知何故groupBy 似乎仍然得分最高。但是,如果这是我选择的唯一列,这将是真正不同的。
$user_names = User::distinct()->count(['name']); 也可以
如果数据库规则不允许任何选择字段位于聚合函数之外,则分组依据将不起作用。请改用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;
});
如果您必须对大型集合进行迭代,则为其添加一个键可以解决性能问题。
【讨论】:
**
**
由于您想从表中获取所有列,您可以收集所有数据,然后使用名为 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();
【讨论】:
请注意,上面使用的 groupBy 不适用于 postgres。
使用distinct 可能是更好的选择 - 例如
$users = User::query()->distinct()->get();
如果您使用query,您可以按要求选择所有列。
【讨论】:
$users = User::select('column1', 'column2', 'column3')->distinct()->get(); 检索表中不同行的所有三个列。您可以添加任意数量的列。
【讨论】:
我发现这种方法(对我来说)工作得很好,可以生成唯一值的平面数组:
$uniqueNames = User::select('name')->distinct()->pluck('name')->toArray();
如果您在此查询构建器上运行 ->toSql(),您将看到它生成如下查询:
select distinct `name` from `users`
->pluck() 由Illumination\collection lib 处理(不是通过sql 查询)。
【讨论】:
在尝试填充用户与其他用户拥有的所有唯一线程的列表时,我遇到了同样的问题。这对我有用
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()
【讨论】:
// Get unique value for table 'add_new_videos' column name 'project_id'
$project_id = DB::table('add_new_videos')->distinct()->get(['project_id']);
【讨论】:
对于那些喜欢我犯同样错误的人。这是详细的答案 在 Laravel 5.7 中测试
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
)
)
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 中的每一行都是不同的。
【讨论】:
$users = Users::all()->unique('name');
【讨论】:
以下是我测试过的 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();
【讨论】: