Trying to convert a query to eloquent - mysql

I have the following SQL:
SELECT arv.*
FROM article_reference_versions arv
INNER JOIN (SELECT `order`,
Max(`revision`) AS max_revision
FROM article_reference_versions
WHERE `file` = '12338-230180-1-CE.doc'
GROUP BY `file`,
`order`) AS b
ON arv.order = b.order
AND arv.revision = b.max_revision
WHERE arv.file = '12338-230180-1-CE.doc'
I need to convert this to Eloquent, so that I can properly access the data in object form. I tried doing it as such,
$s = Models\EloArticleReferenceVersion::select(
'SELECT arv.*
FROM article_reference_versions arv
INNER JOIN (
SELECT `order`, max(`revision`) as max_revision
FROM article_reference_versions
WHERE file = ? group by `file`, `order`) AS b
ON
arv.order = b.order AND arv.revision = b.max_revision
WHERE arv.file = ?',
[
'12338-230180-1-CE.doc',
'12338-230180-1-CE.doc'
])->get();
dd($s);
But I'm running into a plethora of issues, one after another. I figured it'd be easier to just convert this into an eloquent query, looking for some help with this.

DB Query to Query using Eloquent.
$query = EloArticleReferenceVersion::query()
->join(DB::raw('( SELECT `order`,Max(`revision`) AS max_revision FROM article_reference_versions WHERE `file` = '12338-230180-1-CE.doc' GROUP BY `file`, `order`) as sub_table'), function($join) {
$join->on('sub_table.order', '=', 'article_reference_versions.order');
$join->on('sub_table.max_revision ', '=', 'article_reference_versions.revision');
})
->where('article_reference_versions.file', '=', '12338-230180-1-CE.doc' )
->get();
Not Tested

Related

How to join sub-query in laravel elequent

How do this query in laravel query builder ?
select * from products p join
(
select product_id,sum(qty) total_sales
from orders where qty !=0 group by product_id
)
s on p.id = s.product_id
order by s.total_sales desc
There are different ways are there to do the same thing. But you can do with Raw Expressions is very similar to your above code.
if you want to use Eloquent, Do this provided the orders table has product_id that is a foreign key from products
DB::table('products')->join('orders','products.id','orders.product_id')->where('orders.qty','!=',0)->get()
The first part for sub-query for joined part. It is joined with toSql() method inside the raw statement.
$subQuery = DB::table('orders')
->where('qty', '!=', DB::raw(0))
->groupBy('product_id')
->select('product_id', DB::raw('sum(qty) as total_sales'));
return DB::table('products as p')
->join(DB::raw('(' . $subQuery->toSql() . ') s'), 'p.id', '=', 's.product_id')
->orderByDesc('s.total_sales')
->get();
It prints the following sql;
SELECT *
FROM `products` AS `p`
INNER JOIN (
SELECT `product_id`, SUM(qty) AS total_sales
FROM `orders`
WHERE `qty` != 0
GROUP BY `product_id`
) s ON `p`.`id` = `s`.`product_id`
ORDER BY `s`.`total_sales` DESC

How to retrieve 500k records DB data faster?

I have two tables T1 1 000 records and T2 with 500 000 records. I have a query where I run a join between them and fetch data by performing some aggregations. My page seems to be loading slow. Are there any approaches to make this query faster?
I have created indexes on columns for which aggregations are being performed. I think it is a generic statement.
$query = Mymodel::selectRaw("supplier_data.name as distributor,supplier_data.name as name, supplier_data.group_id as group_id, supplier_data.pay,supplier_data.group_id as submitted_group_plan,supplier_data.group_id as group_id_string,
(SELECT sum(t.net_claim) AS trans_number
FROM transactions_data_new as t
JOIN `supplier_data` AS d ON `t`.`member_id` = `d`.`group_id`
WHERE
(
(
t.`submit_date`>= '$date_from' and t.`submit_date`<= '$date_to'
AND t.`member_id` = supplier_data.group_id
)
OR
(
(t.claim_status IS NULL)
AND
(t.submit_date is NULL)
)
)
AND d.id = supplier_data.id
) as trans_number,
(SELECT sum(t.claim) AS trans_number
FROM transactions_data_new as t
JOIN `supplier_data` AS d ON `t`.`member_id` = `d`.`group_id`
WHERE
(
(
t.`submit_date`>= '$date_from' and t.`submit_date`<= '$date_to'
AND t.`member_id` = supplier_data.group_id
)
OR
(
(t.claim_status IS NULL)
AND
(t.submit_date is NULL)
)
)
AND d.id = supplier_data.id
) as claim,
(SELECT sum(t.reversed) AS trans_number
FROM transactions_data_new as t
JOIN `supplier_data` AS d ON `t`.`member_id` = `d`.`group_id`
WHERE
(
(
t.`submit_date`>= '$date_from' and t.`submit_date`<= '$date_to'
AND t.`member_id` = supplier_data.group_id
)
OR
(
(t.claim_status IS NULL)
AND
(t.submit_date is NULL)
)
)
AND d.id = supplier_data.id
) as reversed,
(SELECT sum(t.reversal) AS trans_number
FROM transactions_data_new as t
JOIN `supplier_data` AS d ON `t`.`member_id` = `d`.`group_id`
WHERE
(
(
t.`submit_date`>= '$date_from' and t.`submit_date`<= '$date_to'
AND t.`member_id` = supplier_data.group_id
)
OR
(
(t.claim_status IS NULL)
AND
(t.submit_date is NULL)
)
)
AND d.id = supplier_data.id
) as reversal
");
I don't see the need of this too complex/repeated with same clauses and multiple sub selects for same table which can done using a single left join
SELECT
s.name AS distributor,
s.name AS name,
s.group_id AS group_id,
s.pay,
s.group_id AS submitted_group_plan,
s.group_id AS group_id_string,
SUM(t.net_claim) AS trans_number,
SUM(t.claim) AS claim,
SUM(t.reversed) reversed,
SUM(t.reversal) reversal
FROM
supplier_data s
LEFT JOIN transactions_data_new t
ON `t`.`member_id` = s.`group_id`
AND (
(
t.`submit_date` >= '$date_from'
AND t.`submit_date` <= '$date_to'
)
OR (
t.claim_status IS NULL
AND t.submit_date IS NULL
)
)
GROUP BY s.name,
s.group_id,
s.pay
As I understand it the chunk() method is for use when you need to work with a large dataset and take an action on that data chunk by chunk.
From your question, it sounds like you're performing a query then returning the data as JSON so to me, it doesn't sound like you're taking an action on your dataset that requires chunking.
If you want to break up the returned JSON data you should be instead looking at pagination.
You could apply pagination to your query like so:
$data = Inspector::latest('id')
->select('id', 'firstname', 'status', 'state', 'phone')
->where('firstname', 'LIKE', '%' . $searchtext . '%')
->paginate();
You can specify the size of each set by passing a number to the paginate method:
$data = Inspector::latest('id')
->select('id', 'firstname', 'status', 'state', 'phone')
->where('firstname', 'LIKE', '%' . $searchtext . '%')
->paginate(25);
If I've misunderstood and you did actually want to do the chunking, I believe you could do the following:
$data = Inspector::latest('id')
->select('id', 'firstname', 'status', 'state', 'phone')
->where('firstname', 'LIKE', '%' . $searchtext . '%')
->chunk(50, function($inspectors) {
foreach ($inspectors as $inspector) {
// apply some action to the chunked results here
}
});
Also, if you're returning an eloquent object it will be automatically cast to json so you don't need to perform json_encode() as far as I'm aware.

Convert mysql sub query to Laravel

How I can convert mysql query to laravel query? this is the query
SELECT
users.first_name,
users.id AS uid,
(
SELECT
COUNT(vpl_submissions.accept)
FROM
vpl_submissions
INNER JOIN vpl ON vpl_submissions.vpl = vpl.id
WHERE vpl.courseid = 2
AND vpl_submissions.accept = 1
AND vpl_submissions.userid = uid
) AS completed
FROM
users
INNER JOIN course_enroles ON users.id = course_enroles.user_id
WHERE course_enroles.course_id = 2
You can try this.
DB::table('users')
->join('course_enroles', 'users.id', '=', 'course_enroles.user_id')
->where("course_enroles.course_id", "=", 2)
->select(users.first_name,users.id AS uid,
DB::raw("(SELECT COUNT(vpl_submissions.accept) FROM
vpl_submissions INNER JOIN vpl ON vpl_submissions.vpl = vpl.id
WHERE vpl.courseid = 2
AND vpl_submissions.accept = 1
AND vpl_submissions.userid = uid) as completed")
)
->get();
This will help you.
Until you find a better solution, you can run raw queries like this
$result = DB::select(DB::raw("
select users.first_name,users.id AS uid,
(
select count(vpl_submissions.accept)
FROM vpl_submissions
INNER JOIN vpl on vpl_submissions.vpl = vpl.id
WHERE vpl.courseid=2 AND vpl_submissions.accept =1
AND vpl_submissions.userid = uid
) as completed
from users
inner join course_enroles on users.id = course_enroles.user_id
where course_enroles.course_id = 2
"));

Laravel Eloquent - How to create queries with sub query and if satement

Here is my query
SELECT
IF((SELECT COUNT(*) FROM tablename t WHERE t.field1 = tablename.field1 AND t.field2 IN (50,55,58,60)) = 0,1,0) AS b,
field3,
field4,
FROM tablename
WHERE ProductId = ?
How do I convert it to laravel eloquent?
It would be better if you have shown what you've tried.
That said, this should work:
$result = App\TablenameModel::where('ProductId', 'your_value_here')
->select(
\DB::raw('IF((SELECT COUNT(*) FROM tablename t WHERE t.field1 = tablename.field1 AND t.field2 IN (50,55,58,60)) = 0,1,0) AS b'),
'field3',
'field4'
)
->get();

How do I select columns from results of union of tables using laravel query builder?

I am trying to convert my mysql statement into laravel query builder. In the following query I am trying to do GROUP BY and ORDER BY on the columns which are fetched from the result of UNION-ing three tables
staff_task_history_calibrate
staff_task_history_samples
staff_task_history_measures
Have you guys come across anything similar to it? If yes, could you please shed some light on my issue?
SELECT staff_name, task_id, task_type, task_desc, SUM(task_multiplier)
FROM
(
(
select CONCAT(S.first_name," ",S.last_name) as staff_name,
`STHC`.`task_id`, IFNULL(T.type, "-") as task_type,
`T`.`description` as `task_desc`,
STHC.task_multiplier
from `staff_task_history_calibrate` as `STHC`
inner join `staffs` as `S` on `STHC`.`staff_id` = `S`.`staff_id` inner join `tasks` as `T` on `STHC`.`task_id` = `T`.`id`
)
union
(
select CONCAT(S.first_name," ",S.last_name) as staff_name,
`STHS`.`task_id`, IFNULL(T.type, "-") as task_type,
`T`.`description` as `task_desc`,
STHS.task_multiplier
from `staff_task_history_samples` as `STHS`
inner join `staffs` as `S` on `STHS`.`staff_id` = `S`.`staff_id` inner join `tasks` as `T` on `STHS`.`task_id` = `T`.`id`
)
union
(
select CONCAT(S.first_name," ",S.last_name) as staff_name,
`STHM`.`task_id`, IFNULL(T.type, "-") as task_type,
`T`.`description` as `task_desc`,
STHM.task_multiplier
from `staff_task_history_measures` as `STHM`
inner join `staffs` as `S` on `STHM`.`staff_id` = `S`.`staff_id` inner join `tasks` as `T` on `STHM`.`task_id` = `T`.`id`
)
) combined_tables
GROUP BY staff_name, task_type, task_desc
ORDER BY staff_name, task_type, task_desc;
Difficult for me to test, but try:
// Build up the sub-queries
$sub1 = DB::table('staff_task_history_calibrate AS STHC')
->select(DB::raw(
'CONCAT(S.first_name," ",S.last_name) as staff_name',
'STHC'.'task_id', 'IFNULL(T.type, "-") as task_type',
'T'.'description' as 'task_desc', 'STHC.task_multiplier')
)->join('staffs AS S', 'STHC.staff_id', '=', 'S.staff_id')
->join('tasks AS T', 'STHC.task_id', '=', 'T.id');
$sub2 = DB::table('staff_task_history_samples AS STHS')
->select(DB::raw(
'CONCAT(S.first_name," ",S.last_name) as staff_name',
'STHS'.'task_id', 'IFNULL(T.type, "-") as task_type',
'T'.'description' as 'task_desc', 'STHS.task_multiplier')
)->join('staffs AS S', 'STHS.staff_id', '=', 'S.staff_id')
->join('tasks AS T', 'STHS.task_id', '=', 'T.id');
$sub3 = DB::table('staff_task_history_measures AS STHM')
->select(DB::raw(
'CONCAT(S.first_name," ",S.last_name) as staff_name',
'STHM'.'task_id', 'IFNULL(T.type, "-") as task_type',
'T'.'description' as 'task_desc', 'STHM.task_multiplier')
)->join('staffs AS S', 'STHM.staff_id', '=', 'S.staff_id')
->join('tasks AS T', 'STHM.task_id', '=', 'T.id');
// Add the unions
$allUnions = $sub1->union($sub2)->union($sub3); // (Check the documentation for Unions in Query Builder)
// Get the results
$results = DB::table(DB::raw("({$allUnions->toSql()}) as combined_tables"))
->select('staff_name, task_id, task_type, task_desc')
->sum('task_multiplier')
->mergeBindings($allUnions) // We need to retrieve the underlying SQL
->groupBy('staff_name')
->groupBy('task_type')
->groupBy('task_desc')
->orderBy('staff_name')
->orderBy('task_type')
->orderBy('task_desc')
->get();
(If what you have works, I'd keep it.)