Proper Way of Formatting Where Clause with Alias - Laravel - mysql

I'm stuck on an issue that I'm not quite sure how to properly reformat. Below are the relevant portions of a controller function:
$paidQuery = DB::table('shipments')
->leftJoin('customers', 'shipments.bill_to', '=', 'customers.id')
->leftJoin('customer_addresses', 'shipments.billerLocation', '=', 'customer_addresses.id')
->leftJoin('payments_distributions','shipments.id','=','payments_distributions.shipment_id')
->select('shipments.*', 'customers.customer_name','customer_addresses.billingMethod',DB::raw('COALESCE(sum(payments_distributions.amount),0) AS paid'));
$paidQuery->where('shipments.shipment_origin', 1);
$paidQuery->where('shipments.balance', '<', 'paid')
->where('shipments.balance','>', 0)
->whereNotIn('shipments.shipment_billing_status', [2,3,5]);
if(!empty($_GET['startDate']) || !empty($_GET['endDate'])){
$paidQuery->where(function($query) {
if(empty($_GET['startDate'])){
$startDate = Carbon::create(1900, 1, 1, 0, 0, 0);
} else {
$startDate = $_GET['startDate'];
}
if(empty($_GET['endDate'])){
$endDate = Carbon::now();
} else {
$endDate = $_GET['endDate'];
}
return $query->whereBetween('date', [$startDate, $endDate])
->orWhereNull('date');
});
}
$paidQuery->whereNull('shipments.deleted_at')
->orderBy('shipments.pro_number', 'DESC')
->groupBy('shipments.id')
->limit(100);
Now, as you can see above, there is a select statement (5th line), where at the end is an alias. This is there solely as an example of how the data that I get is returned. I've used it to verify what is and isn't working and that specific line works, the part that doesn't work is this line:
$paidQuery->where('shipments.balance', '<', 'paid')
What would be the proper way to get the sum (or zero (0)) of all of the amount from the payments_distributions table where the record IDs are the same?
I have been looking around and can't find an appropriate example what I am looking for, but am certain it is more likely the search terms or phrasing.
Thanks.

It isn't possible in MySQL to use an alias defined in a select clause in a where clause, at the same level. But, MySQL overloaded the HAVING operator to allow aliases to be used, so the following should work here:
$paidQuery = DB::table('shipments')
->leftJoin('customers', 'shipments.bill_to', '=', 'customers.id')
->leftJoin('customer_addresses', 'shipments.billerLocation', '=', 'customer_addresses.id')
->leftJoin('payments_distributions','shipments.id','=','payments_distributions.shipment_id')
->select('shipments.*', 'customers.customer_name','customer_addresses.billingMethod',DB::raw('COALESCE(sum(payments_distributions.amount),0) AS paid'));
$paidQuery->where('shipments.shipment_origin', 1);
$paidQuery->having('shipments.balance', '<', 'paid');
$paidQuery->where('shipments.balance', '>', 0)
$paidQuery->whereNotIn('shipments.shipment_billing_status', [2,3,5]);
To be clear here, I am suggesting that you use the following raw MySQL:
HAVING paid > shipments.balance

Related

The date returned is todays date instead of what is in the database with Laravel

To start, I have seen this question/answer but it isn't what I'm looking for.
The problem is, I need to be able to return a single result per match of orders.id + order_status_updates.id. When I get a single result the date gives the current date, but change nothing but the query, if I pull in all the results matching what I need but not the latest one I get the correct date/time from the database.
return Order::where('orders.user_id', auth()->id())
->join('order_statuses', 'order_statuses.id', 'orders.order_status_id')
->join('products', 'products.id', 'orders.product_id')
->join('brands', 'brands.id', 'products.brand_id')
->leftJoin('customers', 'orders.customer_id', '=', 'customers.id')
->leftJoin('b2b_businesses', 'b2b_businesses.id', 'orders.b2b_business_id')
->leftJoin('order_status_updates', function($join)
{
$join->select('max(order_status_updates.id) as osid', 'order_status_updates.updated_at');
$join->on('order_status_updates.order_id', '=', 'orders.id');
$join->on('order_status_updates.order_status_id','=', 'orders.order_status_id')
->where('order_status_updates.id', '=', 'osid');
});
Column::callback(['order_statuses.name',
'order_status_updates.updated_at'], function ($orderStatusName,
$orderStatusUpdate) {
$date = new Carbon($orderStatusUpdate);
return '<p>'.$orderStatusName. '</p><p>' . $date->month .'/'. $date->day .'/'. $date->year . '</p>';
})
->label('Status/Date')
->searchable()
->filterable(),
edit: to clarify, all I need to do is take out ->where('order_status_updates.id', '=', 'osid'); and I get the correct time stamp but then lose the return of a single row per match needed.

how to add conditional where clause in sql

Looking for improved answer
In Laravel, I am using a raw query. My question is how to add where clause depending on variable value
i.e. if $cid is present then the query should be
select * from user where aid=2 and cid=1;
If it is not present
select * from user where aid=2;
Ideally, I can do it like this
if($cid) {
$query = DB::select("select * from user where aid=2 and cid=1");
} else {
$query = DB::select("select * from user where aid=2");
}
Is there any way to do this without the above method?
This can be achieved with conditional clauses.
$users = DB::table('users')
->where('aid', 2)
->when($cid, function ($query) {
$query->where('cid', 1);
})
->get();
Please contextualize your question well, we don't know what kind of condition you are talking about, nor in what sense your question is asked.
normally the comment above would be enough but it is necessary to specify
Here are some examples from the documentation
$users = DB::table('users')
->where('votes', '=', 100)
->where('age', '>', 35)
->get();
$users = DB::table('users')->where('votes', 100)->get();
You may also pass an array of conditions to the where function. Each element of the array should be an array containing the three arguments typically passed to the where method:
$users = DB::table('users')->where([
['status', '=', '1'],
['subscribed', '<>', '1'],
])->get();
I encourage you to read the documentation which is very clear on this subject and to come back to me in case of misunderstanding
here

Laravel Query Builder - where clause equals anything programmatically

I'm using Laravel 5.6 - Query Builder.
Is it possible to make a query builder where statement that a value equals everything programmatically?
Let's say that I have this code:
$foo = 1;
DB::table('users')
->select('*')
->where('status', '=', $foo)
->get();
If $foo = 1 then it's straightforward. The query will select everything with the status of 1.
Q: Is it possible to assign something to the $foo variable so the select query returns every record regardless of the status from the DB?
Of course, I can make it happen with 2 query statements like this:
$foo = 1;
if ($foo === null) {
DB::table('users')
->select('*')
->get();
} else {
DB::table('users')
->select('*')
->where('status', '=', $foo)
->get();
}
However, I'm looking for a shorter / more effective solution. Is it possible somehow - without using raw code inside the Where statement?
You may try something like this:
$query = DB::table('users')->select('*');
// $foo = 'get it...';
if ($foo) {
$query->where('status', $foo);
}
$result = $query->get();
Or even more laravel-ish:
$result = DB::table('users')->select('*')
->when($foo, function ($query) use ($foo) {
return $query->where('status', $foo);
})
->get();
Check more here.

Laravel 5.4 Raw Join Query

I have a table TBL_POST used to store blog posts. A post can be assigned to multiple categories, there is a column, cat_id that stores category ID's in comma separated pattern like 2,4,6. I want to use FIND_IN_SET() method in this line
->leftJoin(TBL_CAT.' as c', 'p.cat_id', '=', 'c.id')
to show the associated category names. How can I do that?
public static function getPostWithJoin($status="")
{
$query = DB::table(TBL_POST .' as p')
->select('p.id','p.post_title','p.post_status','u.name as author','c.name as cat_name','p.updated_at')
->leftJoin(TBL_ADMINS.' as u', 'p.post_author', '=', 'u.id')
->leftJoin(TBL_CAT.' as c', 'p.cat_id', '=', 'c.id')
->where('p.post_type','post');
if($status!="all") {
$query->where('p.post_status',$status);
}
$query->orderby('p.id','DESC');
$data = $query->paginate(20);
return $data;
}
You can use callback to create more complicated join query.
->leftJoin(TBL_CAT, function($query){
$query->on(TBL_CAT.'id', '=', 'p.cat_id')->where("**", "**", "**");
})
Here is link on laravel doc - https://laravel.com/docs/5.4/queries#joins "Advanced Join Clauses" section.
UPD::
As mentioned in comment it is not good idea to have string for such types of data. Cause search by equality should be much simpler than string check. Even if your amount of data should not have big difference, you never know what will happen with your app in future.
But if you still want to do that i think you can try like this
->leftJoin(TBL_CAT, function($query){
$query->where(DB::raw("FIND_IN_SET(".TBL_CAT.".id, p.cat_id)"), "<>", "0");
})
Join that will check existence of id in cat_id.

Laravel SUBSTRING on Eloquent query

Question
How do I put a limit on one of the rows in an Eloquent result?
Scenario
I need to retrieve only around 100 characters from one of the fields in my result. Currently I'm using a join statement so multiple results are being returned. I basically need only the first 100 characters from post.content
Code
public function getAll()
{
return Post::select('posts.id', 'posts.title', 'posts.content', 'posts.views', 'posts.comments', 'posts.tags', 'posts.date_created', 'users.image_url', 'users.username', 'users.toxick')
->join('users', 'posts.user_id', '=', 'users.id')
->get();
}
I'm not sure how to go about putting a filter on the query to only return 100 characters. I've looked around briefly but I've not found anything useful, not to my specific scenario at least.
Cant test this at the moment (sorry) but what about:
public function getAll(){
$query = Post::select('posts.id', 'posts.title', 'posts.content','posts.views', 'posts.comments', 'posts.tags', 'posts.date_created', 'users.image_url', 'users.username', 'users.toxick')
->join('users', 'posts.user_id', '=', 'users.id')
->get();
foreach($query as $entries){
$entries->content = substr($entries->content, 1, 100);
}
return $query;
}