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

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.

Related

Need guidance on how to build a Laravel database query

In Laravel 6.18 I'm trying to figure out how to recreate the following Postgres query.
with data as (
select date_trunc('month', purchase_date) as x_month, date_trunc('year', purchase_date) AS x_year,
sum (retail_value) AS "retail_value_sum"
from coins
where user_email = 'user#email.com' and sold = 0
group by x_month, x_year
order by x_month asc, x_year asc
)
select x_month, x_year, sum (retail_value_sum) over (order by x_month asc, x_year asc rows between unbounded preceding and current row)
from data
I know how to build the main part of the query
$value_of_all_purchases_not_sold = DB::table('coins')
->select(DB::raw('date_trunc(\'month\', purchase_date) AS x_month, date_trunc(\'year\', purchase_date) AS x_year, sum(retail_value) as purchase_price_sum'))
->where('user_email', '=', auth()->user()->email)
->where('sold', '=', 0)
->groupBy('x_month', 'x_year')
->orderBy('x_month', 'asc')
->orderBy('x_year', 'asc')
->get();
but how do you build out the with data as ( and the second select?
I need the data to be cumulative and I'd rather do the calculation in the DB than in PHP.
Laravel doesn't have built-in method(s) for common table expression. You may use a third party package such as this - it has a very good documentation. If you don't want to use an external library, then you need use query builder's select method with bindings such as
$results = DB::select('your-query', ['your', 'bindings']);
return Coin::hydrate($results); // if you want them as collection of Coin instance.

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();

Using grouby and sum in a query

I have quite a big query and I'm trying to grab the sum of the orders.price column. With the below code, it returns just 44.00, which is the price for the first row. When I run the raw SQL, it is returning a column with 1,000+ rows of prices in a column called "AGGREGATE". I want to return a single total for all of these prices.
When I remove the groupBy, it works mostly fine. However, the groupby is there as I seem to get duplicate rows back.
$query = Order::leftJoin('customers', 'orders.customer_id', '=', 'customers.customer_id')
->leftJoin('addresses', 'orders.order_id', '=', 'addresses.order_id')
->where('orders.customer_id', '!=', 0);
$query->whereIn('user_id', [3, 5, 10, 15]);
$query->groupBy('orders.order_id');
$sum = $query->sum('orders.price');
I've omitted some of the code here, but the joins are actually necessary.
Here's the generated SQL:
SELECT
sum(`orders`.`price`) AS AGGREGATE
FROM
`orders`
LEFT JOIN `customers` ON `orders`.`customer_id` = `customers`.`customer_id`
LEFT JOIN `addresses` ON `orders`.`order_id` = `addresses`.`order_id`
WHERE
`orders`.`customer_id` IS NOT NULL
AND `orders`.`customer_id` != '0'
AND `orders`.`user_id` IN (3, 5, 10, 15)
GROUP BY
`orders`.`order_id`
ORDER BY
`orders`.`order_id` DESC
You will probably have to replace the JOINs with subqueries:
WHERE EXISTS (
SELECT *
FROM customers
WHERE orders.customer_id=customers.customer_id
AND ...
)
Then you can remove GROUP BY.
If you use relationships:
$query->whereHas('customers', function($query) {
$query->where(...)
})

Converting a raw query to Laravel query builder

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();

eloquent where not in query?

I'm trying to build the following sql query with eloquent. The query gives me all records from table_a which are in the list of ids and do not appear in table_b.
select * from table_a
where id in (1,2,3)
and id not in
(select tablea_id from table_b
where tablea_id in (1,2,3))
So how do I do it in eloquent ? I want to avoid using a raw query.
//does not work
TableA::whereIn('id',$ids)
->whereNotIn('id', TableB::select('tabla_id')->whereIn($ids));
To run a subquery you have to pass a closure:
TableA::whereIn('id',$ids)
->whereNotIn('id', function($q){
$q->select('tabla_id')
->from('tableb');
// more where conditions
})
->get();

Resources