Laravelで非キー列フィールドの個別の値を取得するにはどうすればよいですか?


94

これは非常に簡単かもしれませんが、方法がわかりません。

特定の非キー列フィールドに対して繰り返し値を持つことができるテーブルがあります。その列に異なる値を持つ行をフェッチするQueryBuilderまたはEloquentを使用してSQLクエリを作成するにはどうすればよいですか?

その列だけをフェッチしているのではなく、他の列値と組み合わせているため、distinct()実際には機能しない可能性があることに注意してください。したがって、その質問は基本的に、distinct()パラメータを受け入れないクエリで区別したい列をどのように指定するかということです。

回答:


115

を使用する必要がありますgroupby。クエリビルダでは、次のように実行できます。

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

2
「メッセージ」(チャットに使用)テーブルがあり、認証されたユーザーが各会話から受信した最新のメッセージを取得したいと思います。groupByを使用すると、1つのメッセージしか取得できませんが、最初のメッセージを取得し、最後のメッセージが必要です。orderByが機能しないようです。
JCarlosR 2016

10
SUM、AVG、MAXなどの数学演算を適用したくない場合は、「group by」は正解ではありません(使用できますが、使用しないでください)。個別に使用する必要があります。MySQLでは、列にDISTINCTを使用して、結果セットに列を追加できます:「SELECTDISTINCT name、id、emailFROMusers」。雄弁な場合は、$ this-> select(['name'、 'id'、 'email'])-> distinct()-> get();でこれを行うことができます。
セルギ2017

1
追加するwhere()と壊れますが、どうすれば修正できますか?
TQ

1
これを使用すると、「id」と「email」がgroupBy()にないことが表示されます。groupBy(「id」、「name」、「email」)を使用する必要があります。これは役に立ちません。
haque 2018

1
注意事項:はとgroup by同じではありませんdistinct。SQLクエリ内のgroup byような集計関数の動作を変更しcount()ます。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 2015年

11
@Hirnhamster:オッケイ。ただし、この回答は、通りすがりの人にはまだ役立ちます...
Pathros 2017年

3
私には役に立たない、私は特にOPが何であるかを探しています。それは簡単な発見ではありません。
blamb 2017

1
$users = User::select('column1', 'column2', 'column3')->distinct()->get();
マークヒーロー

また、->orderBy('name')これをで使用する場合にも必要ですchunk
Chibueze Opata

26

雄弁にあなたはこれを使うことができます

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

groupByは実際には個別の値をフェッチしています。実際、groupByは同じ値を分類するため、それらに集計関数を使用できます。ただし、このシナリオでは、集計関数はありません。結果に個別の値を持たせる値を選択するだけです。


4
これはどのように作動しますか?groupByは実際に個別のユーザー名をフェッチしていますか?これがopの問題にどのように答えるかをもう少し説明していただけますか?
フェリックス・ガニオン-グルニエ

はい、groupByは実際には個別の値をフェッチしています。実際、groupByは同じ値を分類するため、それらに集計関数を使用できます。ただし、このシナリオでは、集計関数はなく、結果に個別の値を持たせる値を選択するだけです。
サラール2015年

なるほど..では、この答えはマーシンの答えとどう違うのですか?それがどのように異なり、どのような欠陥が解決されるかを説明できる限り、別の答えを持っていても大丈夫です:)コメントで答えるのを気にせず、関連情報で質問を直接編集してください。
フェリックス・ガニオン-グルニエ

1
結果は同じです。ORMを使用するかクエリビルダーを使用するかはプロジェクトによって異なります。いずれかを使用している場合は、その1つを使用することをお勧めします。だから私はあなたの質問に別の方法で答えました。
サラール2015年

さて、in_array()関数を使用してアイテムが存在するかどうかを確認したい場合、それが機能しないというこの問題があります。それを修正するために、->lists()代わりに試しました(バージョン5.2)。だから、$users = User::select('name')->groupBy('name')->lists('name');phpのためにうまくいきましたin_array();
Pathros 2016年

19

私はこれに答えるのに遅れていますが、Eloquentを使用して個別のレコードを取得するためのより良いアプローチは

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

さて、あなたはフィールド名のパラメータをget()メソッドに渡すこともできることを示すことで付加価値を付けました(そして私はfirst()メソッドにもテストしました)。これはselect()ここのいくつかの回答に示されているメソッドを使用するのと同じです。どういうわけかgroupByまだ最高のスコアのようですが。ただし、これが私が選択している唯一の列である場合、これは本当に明確です。
gthuo 2017年

レコードはエンジン最初に選択することで、グループとは異なり、SQLエンジンに最初にすべてのレコードを選択してから...によって、グループのされますので、賢明な、明確なは、GROUPBY上で得点しようとしているパフォーマンス
rsakhale

1
$user_names = User::distinct()->count(['name']);また動作します
ビラ

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

あなたには良い点があります。この方法は、大規模なコレクションではパフォーマンスが優れていない可能性があり、ページ付けには機能しません。私が持っているものよりも良い答えがあると思います。
JedLynch19年

6

groupBy上記で使用したように、postgresでは機能しないことに注意してください。

使用することdistinctはおそらくより良いオプションです-例えば $users = User::query()->distinct()->get();

を使用するquery場合は、要求に応じてすべての列を選択できます。


6

****

Laravel5.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コレクションのドキュメントを確認してください

編集:Unique()を使用すると、最初にUserテーブルからすべてのデータを取得し、次にLaravelがそれをフィルタリングするため、パフォーマンスに問題がある可能性があります。ユーザーデータがたくさんある場合、この方法は適切ではありません。クエリビルダーを使用して、使用する各フィールドを呼び出すことができます。例:

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

最初にdbからすべてのデータを取得するため、これは効率的ではありません
Razor Mureithi

これがフィルタリングと呼ばれる理由です。クエリビルダーにdistinct()を使用できますが、別のフィールドを取得することはできません(とにかく、selectを使用して各フィールドを呼び出すことができます)。unique()を使用することは、各フィールドを呼び出さずにすべてのフィールドを取得する唯一の方法です(パフォーマンスに問題がある可能性があることはわかっていますが)。
Robby Alvian Jaya Mulia

5

$users = User::select('column1', 'column2', 'column3')->distinct()->get();テーブル内の個別の行の3つの列すべてを取得します。必要な数の列を追加できます。


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

同じ過ちをする私が好きな人のために。これがLaravel5.7でテストされた精巧な答えです

A.DBのレコード

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""select()"、彼らはDBの行ごとに異なっているので、あなたはAとレコードは同じでしょう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.