Converting a raw query to Laravel query builder - laravel

I have the following MySQL query which fetches a list of the last 9 authors to write a post and lists them in order of the date of the last post they wrote.
It's working properly but I'd like to re-write it using the Laravel Query Builder. Here is the query at the moment:
$authors = DB::select("
SELECT
`a`.`id`,
`a`.`name`,
`a`.`avatar`,
`a`.`slug` AS `author_slug`,
`p`.`subheading`,
`p`.`title`,
`p`.`slug` AS `post_slug`,
`p`.`summary`,
`p`.`published_at`
FROM
`authors` AS `a`
JOIN
`posts` AS `p`
ON `p`.`id` =
(
SELECT `p2`.`id`
FROM `posts` AS `p2`
WHERE `p2`.`author_id` = `a`.`id`
ORDER BY `p2`.`published_at` DESC
LIMIT 1
)
WHERE
`a`.`online` = 1
ORDER BY
`published_at` DESC
LIMIT 9
");
I understand the basics of using the query builder, but there doesn't appear to be anything in the Laravel docs that allows for me to JOIN a table ON a SELECT.
Can anyone suggest a way that I can write this query using the Laravel Query builder, or perhaps suggest a way that I can rewrite this query to make it easier to structure with the query builder?

Try to do like this
$data = DB::table('authors')
->select(
'a.id',
'a.name',
'a.avatar',
'a.slug AS author_slug',
'p.subheading',
'p.title',
'p.slug AS post_slug',
'p.summary',
p.published_at')
->from('authors AS a')
->join('posts AS p', 'p.id', '=', DB::raw("
(
SELECT p2.id FROM posts AS p2
WHERE p2.author_id = b.id
ORDER BY p2.published_at
DESC LIMIT 1
)"))
->where('a.online', 1)
->limit(9)
->orderBy('p.published_at', 'desc')
->get();

Related

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']);

GraphQL Where Select Sub Query

These day, i have studied GraphQL with Laravel framework, Lighthouse Library.
I have tried to do kind of SELECT Query.
As a result, I wonder GraphQL can select below SQL Query
SELECT * FROM TABLE_A WHERE type=1 AND chart_id=(SELECT id FROM TABLE_B WHERE phone='0000~~')
I expect, Client first get result from this query.
SELECT id FROM TABLE_B WHERE phone='0000~~'
And then Do Second query, i think i can get a result.
But i wonder I can get result from 1 request. Thanks.
You can try following
$phoneNumber = '0000~~';
$data = DB::table('tableA')->where('type',1)
->whereIn('chart_id',function($query) use ($phoneNumber) {
$query->select('id')
->from('tableB')
->where('phone', '=',$phoneNumber);
})->get();
If there is relationship between tableA and tableB you can do following
TableA::where('type',1)
->whereHas('tableBRelationshipName', function ($q) use ($phoneNumber) {
$q->select('id')
$q->where('phone','=',$phoneNumber);
})->get();

Convert sql query to query builder using laravel 5.4

Hi I my try to convert SQL query to Query Builder. My Sql query below like this
SELECT exclusive_distributor_opens.distribution_code,exclusive_distributor_opens.distribution_name,exclusive_item_opens.item_code,exclusive_item_opens.item_name,SUM(exclusive_budget_items_details.dealer_contribution) as Total,exclusive_distributor_opens.date
FROM exclusive_budget_masters
JOIN exclusive_distributor_opens
ON exclusive_budget_masters.distributor_id=exclusive_distributor_opens.id
JOIN exclusive_budget_items_details
ON exclusive_budget_masters.distributor_id=exclusive_budget_items_details.budget_master_id
JOIN exclusive_item_opens
ON exclusive_budget_items_details.item_id=exclusive_item_opens.id
GROUP BY (exclusive_distributor_opens.distribution_code)
HAVING exclusive_distributor_opens.date BETWEEN '2018-12-19' AND '2018-12-19'
ORDER BY exclusive_distributor_opens.distribution_code DESC
2.My Query Builder Query like this
$results = DB::table('exclusive_budget_masters')
->join('exclusive_distributor_opens', 'exclusive_budget_masters.distributor_id', '=', 'exclusive_distributor_opens.id')
->join('exclusive_budget_items_details', 'exclusive_budget_masters.distributor_id' ,'=', 'exclusive_budget_items_details.budget_master_id')
->join('exclusive_item_opens', 'exclusive_budget_items_details.item_id', '=', 'exclusive_item_opens.id')
->select('exclusive_distributor_opens.distribution_code', 'exclusive_distributor_opens.distribution_name','exclusive_budget_items_details.customar_contribution', DB::raw('SUM(exclusive_budget_items_details.customar_contribution) As Total'))
->whereBetween('exclusive_distributor_opens.date', array('2018-12-19', '2018-12-19'))
->groupBy('exclusive_distributor_opens.distribution_code', 'exclusive_distributor_opens.distribution_name','exclusive_budget_items_details.customar_contribution')
->orderBy('exclusive_distributor_opens.date', 'DESC')
->get();
My Query Output Result Comes like this:
But My Expected Result looks like this:
Please anybody help me.
Why do you expect this to work?
Select part is missing or wrong:
exclusive_item_opens.item_code missing
exclusive_item_opens.item_name missing
exclusive_distributor_opens.date missing
SUM Total column is wrong:
SUM(exclusive_budget_items_details.dealer_contribution) as Total vs
DB::raw('SUM(exclusive_budget_items_details.customar_contribution) As Total')
Your builder query looks like this:
SELECT `exclusive_distributor_opens`.`distribution_code`,
`exclusive_distributor_opens`.`distribution_name`,
`exclusive_budget_items_details`.`customar_contribution`,
Sum(exclusive_budget_items_details.customar_contribution) AS Total
FROM `exclusive_budget_masters`
INNER JOIN `exclusive_distributor_opens`
ON `exclusive_budget_masters`.`distributor_id` =
`exclusive_distributor_opens`.`id`
INNER JOIN `exclusive_budget_items_details`
ON `exclusive_budget_masters`.`distributor_id` =
`exclusive_budget_items_details`.`budget_master_id`
INNER JOIN `exclusive_item_opens`
ON `exclusive_budget_items_details`.`item_id` =
`exclusive_item_opens`.`id`
WHERE `exclusive_distributor_opens`.`date` BETWEEN ? AND ?
GROUP BY `exclusive_distributor_opens`.`distribution_code`,
`exclusive_distributor_opens`.`distribution_name`,
`exclusive_budget_items_details`.`customar_contribution`
ORDER BY `exclusive_distributor_opens`.`date` DESC

Convert SQL to Laravel Eloquent Statement

I've been working on a few tables where through a rather complex relationship (that I'm trying to clean up, but I still need reports made from the data through my Laravel).
At the moment, I can pull the data using the following SQL query to my MySQL database:
SELECT
customers.id,
customers.customer_name,
SUM(shipments.balance) AS shipmentBalance
FROM customers
LEFT JOIN shipments
ON customers.id = shipments.bill_to
AND balance > (SELECT IFNULL(SUM(payments_distributions.amount),0)
FROM payments_distributions
WHERE payments_distributions.shipment_id = pro_number)
GROUP BY customers.id, customers.customer_name
ORDER BY shipmentBalance DESC
LIMIT 5;
I'm just not sure how to rewrite it properly into the whereRaw or DB::raw statements that Laravel Eloquent requires, as my previous attempts have failed.
Update
Here is the closest solution I have tried:
DB::table('customers')
->select('customers', DB::raw('SUM(shipments.balance) AS shipmentBalance'))
->leftJoin(
DB::raw('
(select shipments
ON customers.id = shipments.bill_to
AND balance > (SELECT IFNULL(SUM(payments_distributions.amount),0)
FROM payments_distributions
WHERE payments_distributions.shipment_id = pro_number)'))
->groupBy('customers.id')
->orderByRaw('shipmentBalance DESC')
->limit(5)
->get();
Update 2
Edit for Dom:
Using everything as it stands with your answer, I get the following response:
SQLSTATE[42S22]: Column not found: 1054 Unknown column '' in 'on clause' (SQL: select customers.id, customers.customer_name,SUM(s.balance) AS shipmentBalance from `customers` left join `shipments` as `s` on `customers`.`id` = `s`.`bill_to` and s.balance > (SELECT IFNULL(SUM(payments_distributions.amount),0) FROM payments_distributions WHERE payments_distributions.shipment_id = s.pro_number) = `` group by `customers`.`id`, `customers`.`customer_name` order by SUM(s.balance) DESC limit 5)
But if I remove this section, it brings up the page and the customers (though in the wrong order as I have removed one of the necessary components:
$join->on(DB::raw('s.balance >
(SELECT IFNULL(SUM(payments_distributions.amount),0)
FROM payments_distributions
WHERE payments_distributions.shipment_id = s.pro_number)
'));
Is there anything I can provide you with to get this specific statement to work with your entire answer?
Use this:
DB::table('customers')
->select('customers.id', 'customers.customer_name', DB::raw('SUM(shipments.balance) AS shipmentBalance'))
->leftJoin('shipments', function($join) {
$join->on('customers.id', 'shipments.bill_to')
->where('balance', '>', function($query) {
$query->selectRaw('IFNULL(SUM(payments_distributions.amount),0)')
->from('payments_distributions')
->where('payments_distributions.shipment_id', DB::raw('pro_number'));
});
})
->groupBy('customers.id', 'customers.customer_name')
->orderByDesc('shipmentBalance')
->limit(5)
->get();
Without the Models containing relationships or being able to test on this specific project, this is the most eloquent way I can think of performing your task.
The benefit of starting with the Customer model is you will have a laravel collection and can paginate as needed. Also review the eloquent docs, they help you understand all the different options. Hope his helps.
P.S. Start by using your model in your controller or wherever you are placing this query with:
use App\Customer
The query
$theQuery = Customer::select(DB::raw('customers.id, customers.customer_name,SUM(s.balance) AS shipmentBalance'))
->leftJoin('shipments as s', function($join)
{
$join->on('customers.id', '=', 's.bill_to');
$join->on(DB::raw('s.balance >
(SELECT IFNULL(SUM(payments_distributions.amount),0)
FROM payments_distributions
WHERE payments_distributions.shipment_id = s.pro_number)
'));
})
->groupBy('customers.id', 'customers.customer_name')
->orderByRaw('SUM(s.balance) DESC')
->limit(5)
->get();

Laravel Eloquent - Eager Loading Query is Being Restricted by limit()

I have the following query:
MyTable::where('my_column', '=', 25)->with('myOtherTable')
->orderBy('id', DESC)->limit(5);
I would like the above to bring me results analogoous to the following raw SQL query:
SELECT *
FROM myTable AS ABB1
LEFT JOIN myOtherTable AS ABB2 ON ABB1.id = ABB2.myTable_id
WHERE my_column = 25
ORDER BY myTable.id DESC
LIMIT 5;
The above will find everything in myTable along with corresponding info from myOtherTable and then limit the results to 5 rows.
When I run the eloquent statement above, two SQL queries are processed. The first looks something like:
SELECT *
FROM myTable
WHERE my_column = 25
ORDER BY id DESC;
If this query returns say 7 result items, but I pass in a smaller number into the limit() function (ie. limit(5)), then the corresponding eager loading query will look like:
SELECT *
FROM myOtherTable
WHERE id IN(1, 2, 3, 4, 5);
The eager loading query is itself limited to 5 items. There should be no limit here. The number of items in the IN conditional above should be 7 (or whatever the count returned from the first query is). The limit should only be applied after the second query runs.
How would I do this with Eloquent?
You can use eloquent's join.
MyTable::join('myOtherTable', 'column_id', '=', 'id')
->where('my_column', '=', 25)
->with('myOtherTable')
->orderBy('id', DESC)
->limit(5);
The with is only if you want to eager load the relation on MyTable.

Resources