GraphQL Where Select Sub Query - laravel

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

Related

How to use WITH clause in Laravel Query Builder

I have SQL query (see example).
But I can't find a way how I can write it in Query Builder.
Do you have any ideas how is it possible?
WITH main AS (
SELECT id FROM table1
)
SELECT * FROM table2
WHERE
table2.id IN (SELECT * FROM main)
I want to get format like:
$latestPosts = DB::table('posts')
->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
->where('is_published', true)
->groupBy('user_id');
$users = DB::table('users')
->joinSub($latestPosts, 'latest_posts', function ($join) {
$join->on('users.id', '=', 'latest_posts.user_id');
})->get();
but for WITH
Laravel has no native support for common table expressions.
I've created a package for it: https://github.com/staudenmeir/laravel-cte
You can use it like this:
$query = DB::table('table1')->select('id');
$result = DB::table('table2')
->withExpression('main', $query)
->whereIn('table2.id', DB::table('main')->select('id'))
->get();
Query builder has to be compatible with multiple database engines (mysql, postgresql, sql lite, sql server) and as such only offers support for common functionality.
Assuming your query returns data, you may be able to use the DB:select() method to execute a raw query.
$data = DB::select('WITH main AS (SELECT id FROM table1), SELECT * FROM table2 WHERE table2.id IN (SELECT * FROM main)');
The DB:select method also accepts a second parameter for using named bindings.
Alternatively there are packages available such as laravel-cte that will add the functionality to Eloquent/ Query Builder.

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

Sub-queries in Laravel

I have a query in MySQL
SELECT * FROM group_recordings WHERE id IN ( SELECT MAX(id) FROM group_recordings GROUP BY time_span )
there is a sub-query in "IN" operator, I want to convert this query in laravel eloquent, I have GroupRecording Model. Anyone help me with that
I think the Laravel style of such query will be,
GroupRecording::whereIn('id', function($query) {
$query->selectRaw('MAX(id)')
->from('group_recordings')
->groupBy('time_span');
})
->where('time_span', '>', $recording->time_span)
->get();

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