Laravel에서 키가 아닌 열 필드에 대한 고유 값을 얻는 방법은 무엇입니까?


94

이것은 매우 쉬울 수 있지만 방법을 모릅니다.

특정 키가 아닌 열 필드에 대해 반복되는 값을 가질 수있는 테이블이 있습니다. 해당 열에 대해 고유 한 값이있는 행을 가져 오는 Query Builder 또는 Eloquent를 사용하여 SQL 쿼리를 작성하려면 어떻게해야합니까?

해당 열만 가져 오는 것이 아니라 다른 열 값과 연결되어 있으므로 distinct()실제로 작동하지 않을 수 있습니다. 그래서 그 질문은 기본적으로 distinct()매개 변수 를 허용하지 않는 쿼리에서 구별하려는 열을 지정하는 방법이 될 수 있습니까?

답변:


115

을 사용해야합니다 groupby. Query Builder에서 다음과 같이 할 수 있습니다.

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

2
"메시지"(채팅에 사용됨) 테이블이 있고 인증 된 사용자가 각 대화에서받은 최신 메시지를 받고 싶습니다. groupBy를 사용하면 하나의 메시지 만받을 수 있지만 첫 번째 메시지를 받고 마지막 메시지가 필요합니다. orderBy가 작동하지 않는 것 같습니다.
JCarlosR

10
SUM, AVG, MAX 등과 같은 수학 연산을 적용하지 않으려면 "group by"가 정답이 아닙니다 (사용할 수는 있지만 사용해서는 안 됨). 구별을 사용해야합니다. MySQL에서는 열에 DISTINCT를 사용하고 결과 집합에 "SELECT DISTINCT name, id, email FROM users"열을 추가 할 수 있습니다. eloquent를 사용하면 $ this-> select ([ 'name', 'id', 'email'])-> distinct ()-> get ();
Sergi

1
추가 where()하면 고장이 발생하면 어떻게 해결할 수 있습니까?
tq

1
이것을 사용할 때 'id'가 표시되고 'email'이 groupBy ()에 없습니다. groupBy ( 'id', 'name', 'email')을 사용해야합니다. 유용하지 않습니다.
Haque

1
참고할 사항 : group bydistinct. SQL 쿼리 내부 group by와 같이 집계 함수의 동작을 변경합니다 count(). distinct이러한 기능의 동작은 변경되지 않으므로 사용하는 기능에 따라 다른 결과를 얻을 수 있습니다.
Skeets

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 dec

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의 문제에 어떻게 대답하는지 조금 더 설명해 주시겠습니까?
Félix Gagnon-Grenier

예, groupBy는 실제로 고유 한 값을 가져옵니다. 실제로 groupBy는 동일한 값을 분류하여 집계 함수를 사용할 수 있습니다. 그러나이 시나리오에서는 집계 함수가 없으며 결과가 고유 한 값을 갖도록하는 값을 선택하는 것입니다.
Salar

알겠습니다. 그러면이 답변이 Marcin의 답변과 어떻게 다른가요? 답변이 어떻게 다르고 어떤 결함을 해결하는지 설명 할 수 있다면 다른 답변을해도 괜찮습니다. :) 댓글로 답하지 말고 관련 정보로 질문을 직접 수정하세요.
Félix Gagnon-Grenier

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

성능 측면에서, distinct는 groupBy보다 점수를 매길 것입니다. Group By 엔진이 먼저 모든 레코드를 선택한 다음 group 's by ..
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

당신은 좋은 지적이 있습니다. 이 방법은 대규모 컬렉션에서 성능이 좋지 않을 수 있으며 페이지 매김에는 작동하지 않습니다. 내가 가진 것보다 더 나은 대답이 있다고 생각합니다.
Jed Lynch

6

참고 groupBy위의 사용 포스트 그레스 작동하지 않습니다.

사용하는 distinct것이 아마도 더 나은 옵션 일 것입니다-예 $users = User::query()->distinct()->get();

사용하는 경우 query요청에 따라 모든 열을 선택할 수 있습니다.


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 컬렉션 문서를 확인 하세요.

편집 : Unique ()를 사용하면 먼저 User 테이블에서 모든 데이터를 얻은 다음 Laravel이 필터링합니다. 사용자 데이터가 많은 경우이 방법은 좋지 않습니다. 쿼리 작성기를 사용하고 사용하려는 각 필드를 호출 할 수 있습니다. 예 :

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

db에서 모든 데이터를 먼저 가져
오므로

이것이 필터링이라고 불리는 이유입니다. 쿼리 작성기에 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. 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.