Laravel use result of a table as a join in another select - laravel

I would like to get in laravel 5.2 the same result as this from mysql:
select a3.user_id,sum(a3.task_hour)
from activities a3
where id not in
( select a1.id from activities a1 inner join
(SELECT * FROM `activities` where validated = 1) a2
on a1.user_id = a2.user_id and a1.project_id = a2.project_id where a1.validated = 0)
group by a3.user_id
So in order to get clear view on the code, I try to get the following first:
(SELECT * FROM `activities` where validated = 1) a2
with this
$activity_onlyFromOTL = DB::table('activities AS a2');
$activity_onlyFromOTL->select('a2.id','a2.year','a2.month','a2.user_id','a2.project_id','a2.task_hour')->where('a2.from_otl','=','1');
For the second part, I have this:
( select a1.id from activities a1 inner join
(SELECT * FROM `activities` where validated = 1) a2
on a1.user_id = a2.user_id and a1.project_id = a2.project_id where a1.validated = 0)
For clarity, I tried to use the first variable into this second statement so I can read it better:
$activity_whereOTLandNonOTL = DB::table('activities AS a1');
$activity_whereOTLandNonOTL->select('a1.id');
$activity_whereOTLandNonOTL->join($activity_onlyFromOTL, function ($join) {
$join->on('a1.user_id', '=', 'a2.user_id')->on('a1.project_id', '=', 'a2.project_id');
});
$activity_whereOTLandNonOTL->where('a1.validated', '=' , '0');
But when I try to get the toSql for that one, I get the error:
ErrorException in Grammar.php line 39:
Object of class Illuminate\Database\Query\Builder could not be converted to string
How can I work this way so that it is a much more clear code?

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.

subquery inside orWhere in laravel

I need assistance to build up the query like below in laravel:
SELECT *
FROM table t
WHERE t.a = 1
OR (t.a=0
AND t.id IN (
SELECT o.a_id
FROM other_table o
WHERE o.x > 3
)
);
You could try to build your exact current query, and in fact it might even be the most efficient to write it. But, if we rephrase your query using a left join, it becomes somewhat easier to express in Laravel code.
SELECT *
FROM your_table t
LEFT JOIN other_table o
ON t.id = o.a_id AND o.x > 3
WHERE
t.a = 1 OR
(t.a = 0 AND o.a_id IS NOT NULL);
This would translate to the following Laravel code:
$result = DB::table('your_table t')
->leftJoin('other_table o', function($join) {
$join->on('t.id', '=', 'o.a_id');
$join->on('o.x', '>', '3');
})
->where('t.a', '=', '1')
->orWhere(function($query) {
return $query->where('t.a', '=', '0')
->whereNotNull('o.a_id')
})
->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!!)'));

left join with ActiveRecord (yii2)

I tried to send SQL request with LEFT JOIN but it doesn't display data from table2 table.
public static function top($limit)
{
return self::findBySql("
SELECT * FROM table 1 g1
LEFT JOIN table2 s1
ON (g1.id = s1.g_id AND s1.id = (
SELECT MAX(id)
FROM table2 s2 WHERE s2.g_id = g1.id
))
LIMIT :limit",
[':limit' => $limit]
)->all();
}
It seems you are adding this function to the model and self represents the model itself.
Yii will not return results from another table and will be limited to the model only if you are calling the find on a model, instead you need to use a db query as below:
$query = new \yii\db\Query;
$query->select('*')
->from('table 1 g1')
->leftJoin('table2 s1', 's1.g_id AND s1.id = (SELECT MAX(id) FROM table2 s2 WHERE s2.g_id = g1.id')
->limit($Limit);
$command = $query->createCommand();
$resp = $command->queryAll();
The correct SQL query is
SELECT * FROM table 1 g1
LEFT JOIN table2 s1
ON g1.some_field = s1.some_field
where g1.some_field = s1.some_field are the fields that define the join.
I have working code something like...:)
with user and user_friend_list
$query = new Query;
$query ->select(['user.id AS user_id', 'user_friend_list.id'])
->from('user')
->innerJoin('user_friend_list', 'user.email = user_friend_list.email');
$command = $query->createCommand();
$data = $command->queryAll();
foreach($data as $datakey)
{
//echo $datakey['id'];
$friendfind = UserFriendList::findOne($datakey['id']);
$friendfind->is_app_using_user_id=$datakey['user_id'];
$friendfind->save();
}

how to pass select subquery in where clause using laravel

This is my SQl query
select sum(stock.total_in_stock) as total_in_stock
,stock.name
,stock.inventory_id
from (
select i.store_id
,i.model_id
,i. total_in_stock
,i.id as inventory_id
, m.*
from `inventory` as `i`
left join `model_store` as `ms` on `ms`.`store_id` = `i`.`store_id`
left join `model` as `m` on `m`.`id` = `ms`.`model_id`
where `i`.`model_id` = m.id
and `m`.`status` = 1
and `ms`.`status` = 1
and `i`.`created_at` = (
select si.created_at
from inventory AS si
where si.model_id = i.model_id
and si.store_id = i.store_id
and si.status=1
order by si.created_at desc limit 1
)
) as stock
group by stock.model_id
In laravel, it is written as this:
$results1 = DB::table('inventory as i')
->select(DB::raw( 'sum(stock.total_in_stock) as total_in_stock,stock.name,stock.inventory_id FROM ( SELECT i.store_id,i.model_id,i. total_in_stock,i.id as inventory_id, m.* '))
->leftJoin('model_store as ms','ms.store_id','=','i.store_id')
->leftJoin('model as m','m.id','=','ms.model_id')
->where('i.model_id','=', 'm.id')
->where('m.status','=', '1')
->where('ms.status','=', '1')
->where("i.created_at","=",function($query) {
$query->select(DB::raw("si.created_at FROM inventory AS si WHERE si.model_id = i.model_id AND si.store_id = i.store_id AND si.status=1 ORDER BY si.created_at DESC LIMIT 1)) as stock GROUP BY stock.model_id"));
});
It gives me the following error:-
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1 (SQL: select sum(stock.total_in_stock) as total_in_stock,stock.name,stock.inventory_id FROM ( SELECT i.store_id,i.model_id,i. total_in_stock,i.id as inventory_id, m.* from `inventory` as `i` left join `model_store` as `ms` on `ms`.`store_id` = `i`.`store_id` left join `model` as `m` on `m`.`id` = `ms`.`model_id` where `i`.`model_id` = m.id and `m`.`status` = 1 and `ms`.`status` = 1 and `i`.`created_at` = (select si.created_at FROM inventory AS si WHERE si.model_id = i.model_id AND si.store_id = i.store_id AND si.status=1 ORDER BY si.created_at DESC LIMIT 1 )) as stock GROUP BY stock.model_id))
It takes 2 closing brackets at the end and gives the above error. Please help me writing the above SQL query in laravel.
Answering your question that's in the tile: the subquery where needs fix:
->where("i.created_at", function($query) {
$query->from('inventory as si')
->selectRaw('max(si.created_at)')
->whereRaw('si.model_id = i.model_id AND ...');
});
However, in order to create a subquery in the from clause, you need to pass raw query, so your whole code requires a bit of toSql() and setBindings(...), which is cumbersome.
So to get the answer to your problem, better describe the problem itself instead.

Resources