Laravel'de anahtar olmayan sütun alanları için farklı değerler nasıl elde edilir?


94

Bu oldukça kolay olabilir ama nasıl yapılacağı hakkında hiçbir fikrim yok.

Anahtar olmayan belirli bir sütun alanı için tekrarlanan değerler alabilen bir tablom var. Sorgu Oluşturucu veya Eloquent kullanarak bu sütun için farklı değerlere sahip satırları getirecek bir SQL sorgusu nasıl yazabilirim?

Yalnızca bu sütunu getirmediğimi, diğer sütun değerleriyle bağlantılı olduğunu, bu yüzden distinct()gerçekten çalışmayabileceğini unutmayın. Öyleyse bu soru temelde, artık distinct()hiçbir parametre kabul etmeyen bir sorguda farklı olmasını istediğim sütunun nasıl belirtileceği olabilir ?

Yanıtlar:


116

Kullanmalısınız groupby. Query Builder'da bunu şu şekilde yapabilirsiniz:

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

2
Bir tablo "mesajım" var (sohbet için kullanılır) ve kimliği doğrulanmış kullanıcının her görüşmeden aldığı en son mesajı almak istiyorum. GroupBy kullanarak sadece bir mesaj alabiliyorum, ancak ilk mesajı alıyorum ve son mesaja ihtiyacım var. Görünüşe göre orderBy çalışmıyor.
JCarlosR

10
SUM, AVG, MAX ve benzeri matematik işlemlerini uygulamak istemiyorsanız "gruplama ölçütü" doğru cevap değildir (kullanabilirsiniz, ancak kullanmamalısınız). Farklı kullanmalısınız. MySQL'de bir sütun için DISTINCT kullanabilir ve sonuç kümesine daha fazla sütun ekleyebilirsiniz: "DISTINCT adı, kimliği, kullanıcılardan e-posta seçin". Eloquent ile bunu $ this-> select (['isim', 'id', 'e-posta']) -> farklı () -> get ();
Sergi

1
bir where()itti eklediğimde bunu nasıl düzeltebilirim?
tq

1
bunu kullandığımda 'id' ve 'email' groupBy () içinde değil, groupBy ('id', 'name', 'email') kullanmam gerekiyor. Hangi kullanışlı değil.
Haque

1
Unutulmaması gereken bir şey: group byile aynı şey değil distinct. SQL sorgusu içindeki group bygibi toplama işlevlerinin davranışını değiştirir count(). distinctbu tür işlevlerin davranışını değiştirmeyeceğinden, hangisini kullandığınıza bağlı olarak farklı sonuçlar alırsınız.
Skeets

78

Eloquent'te ayrıca şu şekilde sorgulayabilirsiniz:

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


12
Özellikle Note that I am not fetching that column only, it is in conjunction with other column values
sorulan

12
@Hirnhamster: Okkei. Ancak bu cevap ... hala geçen diğerleri için yararlıdır
Pathros

3
Benim için kullanışlı değil, özellikle OP'nin ne olduğuna bakıyorum. Kolay bir keşif değil.
17'yi 3

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

Ayrıca bunu ->orderBy('name')kullanmak istiyorsanız ihtiyacınız var chunk.
Chibueze Opata

26

anlamlı olarak bunu kullanabilirsin

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

groupBy aslında farklı değerleri getiriyor, aslında groupBy aynı değerleri kategorize edecek, böylece bunlar üzerinde toplama işlevlerini kullanabiliyoruz. ancak bu senaryoda toplama fonksiyonumuz yok, sadece sonucun farklı değerlere sahip olmasına neden olacak değeri seçiyoruz


4
Bu nasıl çalışıyor? GroupBy aslında farklı kullanıcı adlarını alıyor mu? Bunun operasyonun problemini nasıl yanıtladığını biraz daha açıklar mısınız?
Félix Gagnon-Grenier

Yes groupBy aslında farklı değerleri getiriyor, aslında groupBy aynı değerleri kategorize edecek, böylece bunlar üzerinde toplama işlevlerini kullanabiliyoruz. ancak bu senaryoda toplama fonksiyonumuz yok, sadece sonucun farklı değerlere sahip olmasına neden olacak değeri seçiyoruz.
Maaş

Anlıyorum .. öyleyse, bu cevap Marcin'in yanıtından nasıl farklı? Nasıl farklı olduğunu ve hangi kusuru çözdüğünü açıklayabildiğiniz sürece farklı bir cevabın olması uygundur :) Yorumlarda cevaplama zahmetine girmeyin, lütfen sorunuzu ilgili bilgilerle doğrudan düzenleyin.
Félix Gagnon-Grenier

1
sonuç aynıdır, ORM kullanmak veya sorgu oluşturucu kullanmak projenize bağlıdır, eğer bunlardan birini kullanıyorsanız, o zaman buna bağlı kalmak daha iyidir. bu yüzden sorunuzu farklı bir şekilde cevapladım.
Maaş

Pekala, bu sorunu yaşıyorum, şimdi in_array()işlevi kullanarak bir öğenin var olup olmadığını kontrol etmek istiyorsanız , asla çalışmıyor. Düzeltmek için onun ->lists()yerine denedim (Sürüm 5.2). Yani, $users = User::select('name')->groupBy('name')->lists('name');php'ler için iyi çalıştı in_array();
Pathros

19

Bunu yanıtlamakta gecikmeme rağmen, Eloquent kullanarak farklı kayıtlar elde etmek için daha iyi bir yaklaşım

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

Tamam, bize alan adlarının parametrelerinin get()yönteme de aktarılabileceğini göstererek değer kattınız (ve yöntemi de test ettim first()), bu, select()burada birkaç cevapta gösterildiği gibi yöntemi kullanmaya eşdeğerdir . Yine de bir şekilde groupByhala en yüksek puanı alıyor gibi görünüyor. Ancak seçtiğim tek sütun buysa, bu gerçekten farklı olacaktır.
gthuo

Performans açısından, farklı, groupBy'ye göre puan verecek, çünkü kayıtlar önce SQL Engine'de, Group By'den farklı olarak seçilecek. Motor önce tüm kayıtları seçer ve sonra gruplara göre ..
rsakhale

1
$user_names = User::distinct()->count(['name']);ayrıca çalışır
Bira

11

Veritabanı kuralları seçilen alanlardan hiçbirinin bir toplama işlevinin dışında olmasına izin vermiyorsa, göre gruplama çalışmaz. Bunun yerine laravel koleksiyonlarını kullanın .

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

foreach($users->unique('name') as $user){
  //....
}

Birisi bunun büyük koleksiyonlar için performans açısından harika olmayabileceğine dikkat çekti. Koleksiyona bir anahtar eklemenizi tavsiye ederim. Kullanılacak yönteme keyBy adı verilir . Bu basit yöntemdir.

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

KeyBy, daha karmaşık şeyler için bir geri arama işlevi eklemenize de olanak tanır ...

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

Büyük koleksiyonları yinelemeniz gerekiyorsa ona bir anahtar ekleyerek performans sorununu çözebilirsiniz.


Haklısınız ve tam olarak karşı karşıya olduğum sorun bu ... ancak sorgunun yürütülmesini ve koleksiyondaki eylemi gerçekleştirmesini beklemek de ideal değil. Özellikle, sayfalandırmaya bağlıysanız, işleminiz sayfalandırma hesaplamasından sonra olacak ve sayfa başına öğeler yanlış olacaktır. Ayrıca, DB, onu kodda almak ve işlemek yerine büyük veri yığınları üzerinde çalışmak için daha uygundur. Küçük veri parçaları için daha az sorun olur
ChronoFish

İyi bir noktaya temas ettiniz. Bu yöntem, büyük koleksiyonlarda çok iyi performans göstermeyebilir ve bu, sayfalandırma için işe yaramaz. Sanırım sahip olduğumdan daha iyi bir cevap var.
Jed Lynch

6

groupByYukarıda kullanıldığı şekliyle postgres için çalışmayacağını unutmayın .

Kullanmak distinctmuhtemelen daha iyi bir seçenektir - ör. $users = User::query()->distinct()->get();

Eğer kullanırsanız queryistendiği gibi tüm sütunları seçebilirsiniz.


6

**

Laravel 5.8 için test edildi

**

Tablodaki tüm sütunları almak istediğinizden, tüm verileri toplayabilir ve ardından Benzersiz adlı Koleksiyonlar işlevini kullanarak filtreleyebilirsiniz.

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

veya

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

Daha fazla bilgi için Laravel Koleksiyon Belgelerine bakabilirsiniz.

DÜZENLEME: Performansla ilgili sorun yaşayabilirsiniz, Unique () kullanarak tüm verileri önce Kullanıcı tablosundan alırsınız ve ardından Laravel onu filtreler. Çok sayıda Kullanıcı veriniz varsa bu yöntem iyi değildir. Sorgu oluşturucuyu kullanabilir ve kullanmak istediğiniz her alanı çağırabilirsiniz, örneğin:

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

İlk olarak
db'den

Filtreleme olarak adlandırılmasının nedeni budur, sorgu oluşturucu için farklı () kullanabilirsiniz, ancak başka bir alan elde edemezsiniz (yine de her bir alanı select aracılığıyla çağırabilirsiniz). Unique () kullanmak, tüm alanları her birini aramadan elde etmenin tek yoludur (Performansla ilgili bir sorun olabileceğini bildiğimiz halde).
Robby Alvian Jaya Mulia

5

$users = User::select('column1', 'column2', 'column3')->distinct()->get();tablodaki farklı satırlar için üç kulenin tümünü alır. Dilediğiniz kadar sütun ekleyebilirsiniz.


3

Bu yöntemin (benim için) düz bir benzersiz değerler dizisi üretmek için oldukça iyi çalıştığını buldum:

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

->toSql()Bu sorgu oluşturucuyu çalıştırdıysanız , bunun gibi bir sorgu oluşturduğunu göreceksiniz:

select distinct `name` from `users`

Bu ->pluck(), illuminate \ collection lib tarafından işlenir (sql sorgusu ile değil).


1

Bir kullanıcının sahip olduğu tüm benzersiz iş parçacıklarının bir listesini diğer kullanıcılarla doldurmaya çalışırken aynı sorunları yaşadım. Bu benim için hile yaptı

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
$users = Users::all()->unique('name');

5
Lütfen kod pasajınızın OP sorununu NASIL çözdüğünü açıklayın.
ifconfig

0

Aynı hatayı yapmamdan hoşlananlar için. İşte Laravel 5.7'de test edilen ayrıntılı cevap.

A. DB'deki Kayıtlar

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. İstenen Gruplanmış sonuç

UserFile :: select ('tür', 'url', 'güncellenmiş_at) -> farklı (' tür ') -> 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
        )
)

Yani sadece "select()"değerleri aynı olan sütunları içeri aktarın . Örneğin: 'type','url'. Aynı değere sahip olmaları koşuluyla daha fazla sütun ekleyebilirsiniz 'updated_at'.

Eğer geçmek çalışırsanız "created_at"ya "id"yılında "select()"da DB her satır için farklı olduğu için, o zaman A gibi kayıtlar aynı alacak.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.