Raw Laravel query as a collection with conditions - laravel

I've got a fairly complex query that I'd rather not write in Eloquent so I've written it raw. The only problem is that I need to be able to search/filter through the data using the front-end this query is connected to.
This what I've tried but I'm getting an "Call to a member function get() on null" error.
Here's my code:
$report = collect(DB::connection('mysql2')->select("SELECT
t2.holder,
t2.merchantTransactionId,
t2.bin,
t2.last4Digits,
t3.expDate,
(CASE WHEN t3.expDate < CURDATE() THEN 'Expired'
WHEN t3.expDate > CURDATE() THEN 'Due to expire' END) AS expInfo,
t2.uuid
FROM transactions AS t2
INNER JOIN (
SELECT t1.uuid, t1.holder, t1.bin, t1.last4Digits, LAST_DAY(CONCAT(t1.expiryYear, t1.expiryMonth, '01')) AS expDate
FROM transactions t1
JOIN (SELECT t1.merchant_access
FROM total_control.users,
JSON_TABLE(merchant_access, '$[*]' COLUMNS (
merchant_access VARCHAR(32) PATH '$')
) t1
WHERE users.id = :userId
) AS t2
ON t1.merchantUuid = t2.merchant_access
WHERE t1.paymentType = 'RG'
AND t1.status = 1
) t3
ON t2.uuid = t3.uuid
WHERE t3.expDate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND DATE_ADD(CURDATE(), INTERVAL 30 DAY)
GROUP BY t2.holder, t2.bin, t2.last4Digits
ORDER BY t2.holder ASC", ['userId' => $request->userId]))
->when($request->search['holder'], function($q) use ($request) {
$q->where('t2.holder', 'LIKE', '%'.$request->search['holder'].'%');
})->get();
return $report;

Related

Which is the best efficient way to get many-to-many relation count in laravel?

I have students and subjects table in many-to-many relation (pivot table is student_subject).
Student Model
public function subjects()
{
return $this->belongsToMany(Subject::class, 'student_subject');
}
Subject Model
public function students()
{
return $this->belongsToMany(Student::class, 'student_subject');
}
Here I want the particular student subjects counts. I tried the below methods it's working fine but I want the best efficient way for this purpose.
1.
$student = Student::find($id);
$subject_count = $student->subjects()->count();
I checked the SQL query through laravel debuger it shows as below
select * from `students` where `students`.`id` = '10' limit 1
select count(*) as aggregate from `subjects` inner join `student_subject` on `subjects`.`id` = `student_subject`.`subject_id` where `student_subject`.`student_id` = 10 and `subjects`.`deleted_at` is null
$student = Student::withCount('subjects')->find($id);
$subject_count = $student->subjects_count;
I checked the SQL query through laravel debuger it shows as below
select `students`.*, (select count(*) from `subjects` inner join `student_subject` on `subjects`.`id` = `student_subject`.`subject_id` where `students`.`id` = `student_subject`.`student_id` and `subjects`.`deleted_at` is null) as `subjects_count` from `students` where `students`.`id` = '10' limit 1
$student = Student::find($id);
$subject_count = $student->loadCount('subjects')->subjects_count;
I checked the SQL query through laravel debuger it shows as below
select * from `students` where `students`.`id` = '10' limit 1
select `id`, (select count(*) from `subjects` inner join `student_subject` on `subjects`.`id` = `student_subject`.`subject_id` where `students`.`id` = `student_subject`.`student_id` and `subjects`.`deleted_at` is null) as `subjects_count` from `students` where `students`.`id` in (10)
$student = Student::find($id);
$subject_count = DB::table('student_subject')->where('student_id', $student->id)->count();
I checked the SQL query through laravel debuger it shows as below
select * from `students` where `students`.`id` = '10' limit 1
select count(*) as aggregate from `student_subject` where `student_id` = 10
According to the above ways which one is best and why? or if any different best way also there?
Doing relation()->count() is probably faster.
But if all you need is the count, withCount() should be better in terms of memory consumption.

Using same table in subquery

I am failing to convert next SQL code into laravel eloquent:
SELECT t1.template, t1.created_at
FROM sent_emails t1
where created_at = (
select max(created_at) from sent_emails t2 where t2.template = t1.template
)
group by t1.created_at, t1.template
or:
SELECT t1.template, t1.created_at
FROM sent_emails t1
JOIN
(
SELECT Max(created_at) date, template
FROM sent_emails
GROUP BY template
) AS t2
ON t1.template = t2.template
AND t1.created_at = t2.date
group by t1.created_at, t1.template
Both queries return same data set. Creating subquery in separate variable is not an option as I need multiple values to be returned from it.
I also don't know how can I set alias name if I create table using models (and not using DB::), so this is my unsuccessful try:
$sent_emails = SentEmail::where('created_at', function($query) {
SentEmail::where('template', 't1.template')->orderBy('created_at', 'desc');
})->groupBy('template', 'created_at')->get(['template', 'created_at']);
You query should be something like this (I'm not at a computer to test this, so it may require further editing)
$sent_emails = SentEmail::where('created_at', function($query) {
$query->where('created_at', SentEmail::->whereColumn('column_name', 'table.column_name')->orderBy('created_at', 'desc')->max('created_at'));
})->groupBy('template', 'created_at')->get(['template', 'created_at']);

how to create select join multiple condition in laravel 5.3

how to create select join multiple condition in laravel 5.3
SQL SELECT Statement.
SELECT table_1.column_1
,table_2.column_1
,table_3.column_1
FROM table_1
LEFT JOIN table_2
ON table_1.column_1 = table_2.column_1
LEFT JOIN table_3
ON table_1.column_2 = table_3.column_2
AND table_3.column_3 <= NOW()
AND ( table_3.column_4 >= NOW()
OR table_3.column_4 = 0
)
WHERE table_1.column_1 = '0000000001'
I want to convert SQL Statement to laravel select.
I try.
$result = DB::table('table_1')
->select('table_1.column_1', 'table_2.column_1', 'table_3.column_1')
->leftJoin('table_1', 'table_1.column_1', '=', 'table_2.column_1')
->leftJoin('table_3', 'table_1.column_2', '=', 'table_3.column_2')
->where('table_1', $_POST['id'])
->get();
DB::table('table_1')
->select('table_1.column_1', 'table_2.column_1', 'table_3.column_1')
->leftJoin('table_1', 'table_1.column_1', '=', 'table_2.column_1')
->leftJoin('table_3', 'table_1.column_2', '=', 'table_3.column_2')
->where('table_1.column_1', $_POST['id'])
->where('table_3.column_3','>=', NOW())
->where(function($query) {
$query->where('table_3.column_4', '>=', NOW())
->orWhere('table_3.column_4','0');
})
->get();

laravel query builder from normal query

DB::select(DB::raw( 'SELECT a.bill_no, a.account_id, a.bill_date, a.amount_paid,
b.transaction_code,b.amount from bill_det a left join
(select bill_no, transaction_code, sum(amount) as amount from payment_transactions
where status = "success" group by bill_no ) b
on a.bill_no = b.bill_no where a.amount_paid != b.amount order by b.bill_no'));
this is normal query.change into laravel query?.
i tried.
$bill=DB::table('bill_det')->leftJoin('payment_transactions', 'bill_det.bill_no', '=', 'payment_transactions.bill_no')
->select('bill_det.bill_no','bill_det.account_id','bill_det.bill_date','bill_det.amount_paid',
'payment_transactions.transaction_code',DB::raw('sum(payment_transactions.amount) as amount'))
->where('payment_transactions.status','=','success')
->where('sum(payment_transactions.amount)','!=',DB::raw('bill_det.amount_paid'))
->groupBy('bill_det.bill_no')
->orderBy('bill_det.bill_no','desc');
i can't compare -> where('sum(payment_transactions.amount)','!=',DB::raw('bill_det.amount_paid'))
i used like this ->whereRaw('bill_det.amount_paid != sum(payment_transactions.amount)')
{"error":{"type":"Illuminate\Database\QueryException","message":"SQLSTATE[HY000]: General error: 1111 Invalid use of group function (SQL: select count(*) as aggregate from (select '1' as row_count from bill_det left join payment_transactions on bill_det.bill_no = payment_transactions.bill_no where payment_transactions.status = success and bill_det.amount_paid != sum(payment_transactions.amount) group by bill_det.bill_no order by bill_det.bill_no desc) count_row_table)"
DB::select(DB::raw( 'SELECT a.bill_no, a.account_id, a.bill_date, a.amount_paid,
b.transaction_code,b.amount from bill_det a left join
(select bill_no, transaction_code, sum(amount) as amount from payment_transactions
where status = "success" group by bill_no ) b
on a.bill_no = b.bill_no where a.amount_paid != b.amount order by b.bill_no'));
After converting this to laravel Query::
$query = \Illuminate\Support\Facades\DB::table('bill_det')
->select('a.bill_no', 'a.account_id', 'a.bill_date', 'a.amount_paid', 'b.transaction_code', 'b.amount')
->leftJoin(DB::raw('(select bill_no, transaction_code, sum(amount) as amount from payment_transactions
where status = "success" group by bill_no) b'), function($join) {
$join->on('a.bill_no', '=', 'b.bill_no');
})
->where('a.amount_paid','<>', 'b.amount')
->orderBy('b.bill_no')
->get();
In case you want to know how to use raw expression inside where then use this:
$query->whereRaw(DB::raw('(your expression!!)'));

Eloquent query by aggregated relation

I would like to make a query by an aggregated value from the model relations.
As example I should get only Posts which has the last comment between two dates.
SELECT posts.*, MAX(comments.created_at)
as max FROM posts
JOIN comments ON (comments.post_id = posts.id)
GROUP BY posts.id HAVING max > '2014-01-01 00:00:00' AND max < '2014-02-01 00:00:00'
Instead of joins use builtin methods:
// Assuming you have relations setup
Post::whereHas('comments', function ($q) use ($from, $till) {
$q->groupBy('post_id')
->havingRaw("max(created_at) between '{$from}' and '{$till}'");
})->get();
It will produce:
select * from `posts` where
(select count(*) from `comments` where `comments`.`post_id` = `posts`.`id`
group by `post_id`
having max(created_at) between '2014-01-01' and '2014-02-01'
) >= 1 limit 1

Resources