如何在Laravel中为非关键列字段获取不同的值?


94

这可能很容易,但不知道如何做。

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

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

Answers:


115

您应该使用groupby。在查询生成器中,您可以按照以下方式进行操作:

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

2
我有一个表“ messages”(用于聊天),并且我想获取经过身份验证的用户从每个对话中收到的最新消息。使用groupBy我只能收到一条消息,但是我收到第一条消息,而我需要最后一条消息。似乎orderBy不起作用。
JCarlosR '16

10
如果您不想应用任何数学运算(例如SUM,AVG,MAX等),“ group by”都不是正确的答案(可以使用它,但不应该使用它)。您应该使用与众不同。在MySQL中,您可以将DISTINCT用于列,并将更多列添加到结果集中:“ SELECT DISTINCT名称,ID,来自用户的电子邮件”。雄辩地说,您可以使用$ this-> select([['name','id','email'])-> distinct()-> get();来实现。
塞尔吉(Sergi)

1
当我添加一个where()中断时,该如何解决?
tq

1
当我使用它时,它显示'id'和'email'不在groupBy()中,我需要使用groupBy('id','name','email')。这没有用。
哈克

1
注意事项:group by与并不相同distinctgroup by将更改聚合函数的行为,例如count()在SQL查询内部。distinct不会改变此类功能的行为,因此您会根据使用哪种功能而获得不同的结果。
飞碟

76

在Eloquent中,您还可以这样查询:

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


11
问题专门提出Note that I am not fetching that column only, it is in conjunction with other column values
Hirnhamster

11
@Hirnhamster:Okkei。但是,此答案对于过路的其他人仍然有用...
Pathros

3
对我来说没有用,我专门查看OP是什么。这不是一个容易的发现。
blamb

1
$users = User::select('column1', 'column2', 'column3')->distinct()->get();
Mark-Hero

另外你需要->orderBy('name'),如果你想使用这项功能chunk
Chibueze Opata

26

雄辩的你可以用这个

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

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


4
这是如何运作的?groupBy实际上是在获取不同的用户名吗?您能否再说明一下这如何解决op的问题?
费利克斯·加侬-格雷尼尔

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

我知道..那么,这个答案与Marcin的答案有何不同?只要您可以解释它的不同之处和解决的缺陷,就可以有一个不同的答案。)
费利克斯·加侬-格雷尼尔

1
结果是相同的,取决于您的项目使用ORM还是使用查询生成器,如果您使用的是其中之一,则最好坚持使用它。这就是为什么我用不同的方式回答了您的问题。
撒拉族(Salar)

好吧,我有一个问题,如果您现在想使用该in_array()功能检查某个项目是否存在,它将永远无法使用。要解决此问题,我尝试->lists()改用(5.2版)。因此,$users = User::select('name')->groupBy('name')->lists('name');对于php来说效果很好in_array()
Pathros

19

尽管我来不及回答这个问题,但是使用Eloquent获得更好记录的更好方法是

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

好的,您已经向我们展示了也可以将字段名称的参数传递给get()方法(并且我也已经对该first()方法进行了测试),从而增加了价值,这等效于使用select()此处的一些答案所示的方法。虽然groupBy似乎仍然得分最高。但是,如果这是我选择的唯一列,则这将是真正不同的。
gthuo

在性能方面,不同的是要得分超过GROUPBY,因为记录将首先在SQL引擎组选择不同发动机首先选择的所有记录,然后将集团由..
rsakhale

1
$user_names = User::distinct()->count(['name']);也有效
Bira

11

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

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

如果必须遍历大型集合,则向其添加密钥可以解决性能问题。


您是正确的,而这正是我要解决的问题...但是,等待查询执行并在集合中执行操作也不理想。特别是如果您依靠分页,则将在分页计算之后进行操作,并且每页的项目将是错误的。而且,DB更适合于对大型数据块进行操作,而不是通过代码进行检索和处理。对于小数据块,这将不再是一个问题
ChronoFish

你有一个好点。在大型馆藏中,此方法可能不是很好的性能明智选择,并且它不适用于分页。我想我有一个更好的答案。
杰德·林奇

6

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

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

如果使用query,则可以根据要求选择所有列。


6

**

经过Laravel 5.8测试

**

由于您想从表中获取所有列,因此您可以收集所有数据,然后使用称为“唯一”的“收集”功能对其进行过滤

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

要么

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

有关更多信息,您可以查看Laravel Collection文档

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

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

由于您首先从数据库获取所有数据,因此效率不高
Razor Mureithi

这就是所谓的过滤的原因,您可以对查询构建器使用distinct(),但无法获取其他字段(无论如何,您仍然可以通过select调用每个字段)。通过使用unique()是获取所有字段而不调用每个字段的唯一方法(尽管我们知道性能可能会出现问题)。
Robby Alvian Jaya Mulia

5

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


3

我发现此方法(对我而言)非常有效,可以生成唯一值的平面数组:

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

如果您->toSql()使用此查询构建器,将看到它生成如下查询:

select distinct `name` from `users`

->pluck()是通过照射\收集LIB(不是通过SQL查询)来处理。


1

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

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


0

对于喜欢我的人犯同样的错误。这是在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'

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.