just_chris
just_chris

Reputation: 154

Laravel Eloquent Query Multiple records based on set criteria

I have a form where my users can set Criteria to search their customer database, however I am struggling to pull the query together for this (working in Laravel 5.7).

Currently the criteria customers can set is as follows:

I am now trying to get my head around how I can build this into a query, I can’t even produce a tangible example! My hurdle seems to be checking the first record & the last record to make sure it meets the criteria.

SQLFiddle: http://sqlfiddle.com/#!9/68407/1

My Table:

|  id  | name           | email                                       | provider    | created_at
---------------------------------------------------------------------------------------
 | 1 | Mr Smith        | [email protected]         | facebook | 2018-11-01 09:00:00 | 
 | 2 | Mrs Smith      | [email protected]      | facebook  | 2018-11-01 09:00:00 | 
 | 3 | Miss Smith     | [email protected]    | email        | 2018-11-01 09:00:00 | 
 | 4 | Doctor Smith | [email protected] | email        | 2018-11-01 09:00:00 | 
 | 5 | Lord Smith    | [email protected]      | twitter      | 2018-11-01 09:00:00 | 
 | 6 | Lady Smith    | [email protected]      | email        | 2018-11-01 09:00:00 | 
 | 7 | Mr Smith        | [email protected]         | facebook | 2018-11-02 09:00:00 | 
 | 8 | Mrs Smith      | [email protected]       | facebook  | 2018-11-02 09:00:00 | 
 | 9 | Doctor Smith | [email protected]  | email        | 2018-11-02 09:00:00 | 
 | 10 | Lord Smith   | [email protected]       | twitter      | 2018-11-02 09:00:00 | 
 | 11 | Lady Smith   | [email protected]      | email        | 2018-11-02 09:00:00 | 
 | 12 | Mr Smith      | [email protected]         | facebook | 2018-11-03 09:00:00 | 
 | 13 | Mrs Smith    | [email protected]       | facebook | 2018-11-03 09:00:00 | 
 | 14 | Miss Smith   | [email protected]     | email        | 2018-11-03 09:00:00 | 
 | 15 | Lord Smith   | [email protected]       | twitter      | 2018-11-03 09:00:00 | 
 | 16 | Lady Smith  | [email protected]      | email        | 2018-11-03 09:00:00 | 

Example customer criteria for the query:

Current query:

    $Customers = Customer::groupBy('email')
                 ->havingRaw('COUNT(*) > 2’)
                 ->where('created_at', '<', Carbon::now()->subDays(2)->toDateTimeString())
                 ->get();

I can’t figure out how to pull the first customer record check that it more than 2 days old, and then pull their last record and make sure it is more than 1 day old. I know that my current query is completely useless for what I am trying to achieve, but again I am struggling to pull this together.

Expected results:

|  id  | name           | email                                       | provider    | created_at
---------------------------------------------------------------------------------------
 | 12 | Mr Smith      | [email protected]         | facebook | 2018-11-03 09:00:00 | 
 | 13 | Mrs Smith    | [email protected]       | facebook | 2018-11-03 09:00:00 | 

Upvotes: 0

Views: 421

Answers (2)

Oluwafemi Sule
Oluwafemi Sule

Reputation: 38952

The SQL query in the MySQL dialect to make that selection is as follow

SELECT id, name, email, provider, created_at
FROM customers 
WHERE provider = 'facebook'
GROUP BY email
HAVING 
  count(*) > 2
  AND min(created_at) < date_sub(now(), interval 2 day)
  AND max(created_at) < date_sub(now(), interval 1 day)

That can be translated as an Eloquent query like so

$havingClause = 'count(*) > ? AND min(created_at) < ? AND max(created_at) < ?';
$havingClauseBindings = [
   2,
   Carbon::now()->subDays(2)->toDateTimeString(),
   Carbon::now()->subDays(1)->toDateTimeString()
];
$customers = Customer::where('provider', 'facebook')
                       ->groupBy('email')
                       ->havingRaw($havingClause, $havingClauseBindings)
                       ->get();

Upvotes: 1

Elie
Elie

Reputation: 321

The query you are looking for is:

select * from customers group by email having count(*) > 2 and min(created_at) <= '2018-10-02 09:00:00' and max(created_at) <= '2018-10-03 09:00:00' and provider = 'facebook'

assuming the current time is 2018-10-04 09:00:00.

In eloquent:

$Customers = Customer::groupBy('email')
             ->havingRaw('COUNT(*) > 2')
             ->havingRaw('max(created_at) < ?' , [Carbon::now()->subDays(2)->toDateTimeString()])
             ->havingRaw('min(created_at) < ?' , [Carbon::now()->subDays(1)->toDateTimeString()])
             ->havingRaw('provider = ?' , ['facebook'])
             ->get();

On a separate note, using eloquent you can chain methods, like the following

$customers = Customer::groupBy('email');

if( $includeCount ) {

     $customers->havingRaw('COUNT(*) > 2');
}
...
...
...

Upvotes: 2

Related Questions