4

I am using Laravel 5.5.

I have a database which contains users. The problem is that some users exist more than one time because of a bug. I want to query my database and select all "unique" users.

By using the word "unique" I mean the below :

If a user with email "test@test.com" exists 50 times I want the row that created_at is closest to now.

My query, which returns all users is written below :

DB::table('users')
  ->select('name', 'surname', 'email', 'phone', 'answers', 'newsletter', 'created_at')
  ->get();

I got confused and I'm not sure if i should use limit combining it with order by created_at column.

Any ideas?

M Khalid Junaid
  • 63,861
  • 10
  • 90
  • 118
Antonios Tsimourtos
  • 1,676
  • 1
  • 14
  • 37

4 Answers4

3

Ok, this is what you need to do: First off, you get a table with the users in their last created_at 'version'. Now you have a list of emails and dates. Then you perform a left join of all the users with that temporary table.

TL;DR:

    $users = DB::select('select t1.* from users t1 right join (SELECT email, MAX(created_at) as created_at from users group by email) as t2 on t1.email=t2.email and t1.created_at=t2.created_at');

I hate raw SQL, and I hate subqueries, but this is the only way I know using generic SQL (I mean, you could do a better MySQL or MSSQL native queries, but this should do for you.)

Amarnasan
  • 14,939
  • 5
  • 33
  • 37
  • This does return users but i think it needs a modification. I have a total of 8000 users but only ~900 are "unique". Your `$users` has the 900 users but also has the rest 7100 - but they don't have the `email`. Could i just have the 900? – Antonios Tsimourtos Dec 13 '17 at 11:50
  • Shoot, you're right. use right join instead of left join and only t1.* instead of * ... query updated – Amarnasan Dec 13 '17 at 11:53
0

You can use

DB::table('users')->select('name', 'surname', 'email','phone','answers','newsletter','created_at')->orderBy('created_at', 'desc')->groupBy('email')->get();

For more help refer Order By before Group By using Eloquent (Laravel)

Ankur Tiwari
  • 2,762
  • 2
  • 23
  • 40
0

What you need is groupby and orderby

try this code

DB::table('users')->select('name', 'surname', 'email','phone','answers','newsletter','created_at')
                  ->orderBy('created_at', 'desc')
                  ->groupBy('email')
                  ->get();

hope it will help you if you need further info try above link!

Gaurav Gupta
  • 1,588
  • 2
  • 14
  • 21
0

To get latest user record among duplicates you can use a self join

DB::table('users as u')
  ->select('u.*')
  ->leftJoin('users as u1', function ($join) {
        $join->on('u.email', '=', 'u1.email')
             ->whereRaw(DB::raw('u.created_at < u1.created_at'));
   })
  ->whereNull('u1.id')
  ->get();

In plain SQL it would be something like

select u.*
from users u
left join users u1 on u.email = u1.email
and u.created_at < u1.created_at
where u1.id is null
M Khalid Junaid
  • 63,861
  • 10
  • 90
  • 118