Count where query in Laravel - mysql

I am having a issue here that I am not solving.
I am trying to make a query in Laravel where I need to count how many offers does a business has, to show Business id, Total Offers for a Business and Business Name.
$business_offers = DB::table('offers')
->join('businesses', 'offers.id_business', '=', 'businesses.id')
->select(['businesses.id', 'businesses.name', DB::raw('count(offers.id) as total_offers')])
->orderby('total_offers', 'DESC')
->get();
but it is not working in this way. I have also done the query in mysql but can't integrate it in Laravel.
SELECT bu.id,(SELECT count(of.id) from offers of where of.id_business = bu.id )
as total_offers, bu.`name` from businesses bu ORDER BY total_offers DESC
thanks in advance

Reading it literally something like the following might work:
$business_offers = DB::table('businesses bu')
->select(['bu.id', DB::raw("(SELECT count(of.id) from offers of where of.id_business = bu.id )") ,'bu.name'])
->orderBy('total_offers', 'DESC')
->get();
If you want it a bit more efficient (maybe):
$business_offers = DB::table('offers')
->join('businesses', 'offers.id_business', '=', 'businesses.id')
->select(['businesses.id', DB::raw("COUNT(1) as total_offers"),'businesses.name'])
->groupBy("businesses.id","businesses.name")
->orderBy('total_offers', 'DESC')
->get();

If you have models and relations set up it should be as easy as:
$businesses = Business::withCount(['offers'])->get;
foreach ($businesses as $business) {
echo $business->offers_count;
}
From the Laravel documentation:
If you want to count the number of results from a relationship without
actually loading them you may use the withCount method, which will
place a {relation}_count column on your resulting models.
All you need in your Business model is:
class Business extends Model
{
/**
* Get all of the offers for the business.
*/
public function offers()
{
return $this->hasMany('App\Offer');
}
}
and in the Offer model:
class Offer extends Model
{
/**
* Get the business for the current offer.
*/
public function business()
{
return $this->belongsTo('App\Business', 'business_id');
}
}

Related

Laravel - Query builder with subquery

So i have a pivot table like the following :
match id
player id
score
And i want to query to get the number of wins/losses for a given user id. (wins based on user id with the highest score for a game)
In sql i would write this like :
SELECT user_id, score
from match_user matchu1
where score = (select max(score) from match_user matchu2 where matchu1.match_id = matchu2.match_id)
How would i express this query in laravel, or is there a better method of doing this that i am missing ?
There are multiple ways to achieve this. The easiest and cleaniest way to me is defining
a relationship with pivot.
class Match extends Model
{
public function players()
{
return $this->belongsToMany(User::class, 'match_user')->withPivot('score');
}
public function winner()
{
return $this->players
->sortByDesc(function ($player) {
return $player->pivot->score;
})
->first();
}
}
Then you can simply get the winner by saying:
$match->winner();
This is to answer your true intention of asking this question, which is to get the number of wins for a single user, as you commented on my answer. The following the the best solution that I can think of for now:
class Match extends Model
{
public function scopeWonBy($query, User $user)
{
return $query->selectRaw('matches.id, max(match_user.score) AS max_store, match_user.player_id AS player_id')
->join('match_user', 'matches.id', '=', 'match_user.match_id')
->groupBy('matches.id')
->having('player_id', $user->id);
}
}
Later on, you can say:
$matches = Match::wonBy($user);
$count = Match::wonBy($user)->count();
I'm not going to write your query for you as I don't want to provide an untested solution but the following code example should give you a good idea of how to implement subqueries with the query builder.
$q->where('price_date', function($q) use ($start_date)
{
$q->from('benchmarks_table_name')
->selectRaw('min(price_date)')
->where('price_date', '>=', $start_date)
->where('ticker', $this->ticker);
});

Laravel join use to get one to many relations?

Is there any way to get relational data ( one to many relation records ) using joins in laravel without creating different records in collection :
Example:
$orders = DB::table('orders')
->join('users', 'users.id', '=', 'orders.users_id')
->join('order_items', 'order_items.order_id', '=', 'orders.id')
->select('users.*', 'order_items.*')
->get();
So here what's happening is that its creating 6 records if order has 6 items but i want something like single records in which it has array or collection where are order items are listed.
Output I want is generally of this order:
Collection {# ▼
#items: array:[▼
0 => {
+'id':1,
...,
+ 'items: [
//here i want all the records of relation order items
]
}
]
}
Is there any way to achieve this result without using with() or load() and just only with joins or raw queries?
You should try this:
$orders = DB::table('orders')
->select('users.*', 'order_items.*')
->leftJoin('users', 'users.id', '=', 'orders.users_id')
->leftJoin('order_items', 'order_items.order_id', '=', 'orders.id')
->get();
This answer is speculative, but perhaps you want to report a single row for each user, with a CSV list of order items:
$orders = DB::table('orders AS o')
->join('users AS u', 'u.id', '=', 'o.users_id')
->join('order_items AS oi', 'oi.order_id', '=', 'o.id')
->select('u.id', DB::raw('GROUP_CONCAT(oi.name) AS orders'))
->groupBy('u.id')
->get();
If there's no reason stopping you from using the Eloquent, is the best way for working with databases.
The Eloquent ORM included with Laravel provides a beautiful, simple
ActiveRecord implementation for working with your database
Here is the Documentation Eloquent: Getting Started
The model relationship made easy in laravel, you can get you want as following:
The User model relationships:
//user orders
public function orders() {
return $this->hasMany('App\Order');
}
The Order model relationships:
//order items
public function items() {
return $this->hasMany('App\OrderItem');
}
//order owner
public function user() {
return $this->belongsTo('App\User');
}
The OrderItem model relationships:
//order
public function order() {
return $this->belongsTo('App\Order');
}
Here is a quick example of how you may get the order's items
$orders = User::find($id)->orders
foreach($orders as $order) {
$orderItems = $order->items;
}
you can make the collection the way you prefer, but strongly recommend using Eloquent Resources, since most apps these days expecting JSON responses.

Laravel: orderBy relationship's field

I have an issue with ordering model by it's relationship's latest object field.
I have a class named Coin that is related to DailyPrices, that 1 coin can have many DailyPrices. I want to sort coins by latest DailyPrices field named vol.
I tried doing
$coins = Coin::join('daily_prices', 'daily_prices.coin_id', '=', 'coins.id')
->orderBy('daily_prices.vol', 'desc')
->paginate(100);
and many variations about it, but I can't get it to work. What am I doing wrong?
why don't you use created_at instead of vol
$coins = Coin::join('daily_prices', 'daily_prices.coin_id', '=', 'coins.id')->order_by('created_at', 'desc')->paginate(100);
You can do with creating two separate model for coin and daily price.
class Coin extends Model {
public function dailyPrices(){
return $this->hasMany('App\DailyPrice')->orderBy('vol', 'DESC');
}
}
class DailyPrice extends Model {
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'daily_prices';
/**
* Get the coin that owns the daily price.
*/
public function coin()
{
return $this->belongsTo('App\Coin');
}
}
and call with ID in your controller like this
$coinData = Coin::find($coin_id)->with('dailyPrices')->first();
You made two mistakes in your code:
Condition check
Not select table
Here is a code after making changes:
$order='desc';
Coin::join('daily_prices', 'coins.id', '=', 'daily_prices.coin_id')->orderBy('daily_prices.vol', $order)->select('coins.*')->paginate(100);
You can also see more details from here:Order by on relationship
You can use One to Many relationship :
class Coin {
public function dailyPrices() {
return $this->hasMany(DailyPrice::class);
}
}
DailyPrice :
class DailyPrice {
public function coin() {
return $this->belongsTo(Coin::class);
}
}
Then in your controller :
Coin::with('dailyPrices' => function ($query) {
$query->orderBy('vol', 'desc');
))->paginate(100);
The with function will load dailyPrice relationship on your item and the value argument will execute a query related to the relation loaded (here an order by).
Hopes it helps you.
Maybe the question was unclear, I don't know. But neither of these were relevant to an issue. I have resolved the problem with this query:
SELECT c.* FROM daily_prices AS dp JOIN coins AS c ON dp.coin_id=c.id WHERE dp.id IN (SELECT MAX(id) FROM daily_prices GROUP BY coin_id) ORDER BY vol DESC
and transformed to laravel call:
Coin::join('daily_prices', 'daily_prices.coin_id', '=', 'coins.id')
->whereIn('daily_prices.id', function ($query) {
$query->selectRaw('MAX(id)')
->from('daily_prices')
->groupBy('coin_id');
})
->orderBy('daily_prices.vol', 'desc')
->paginate(100);

Laravel - Eloquent - Filter based on latest HasMany relation

I have this two models, Leads and Status.
class Lead extends Model
{
public function statuses() {
return $this->hasMany('App\LeadStatus', 'lead_id', 'id')
->orderBy('created_at', 'DESC');
}
public function activeStatus() {
return $this->hasOne('App\LeadStatus', 'lead_id', 'id')
->latest();
}
}
class LeadStatus extends Model
{
protected $fillable = ['status', 'lead_id'];
}
This works fine, now I'm trying to get all Leads based on the 'status' of the last LeadStatus.
I've tried a few combinations with no success.
if ($search['status']) {
$builder = $builder
->whereHas('statuses', function($q) use ($search){
$q = $q->latest()->limit(1);
$q->where('status', $search['status']);
});
}
if ($search['status']) {
$builder = $builder
->whereHas('status', function($q) use ($search){
$q = $q->latest()->Where('status', $search['status']);
});
}
Has anybody done this with Eloquent? Do I need to write some raw SQL queries?
EDIT 1: I'll try to explain again :D
In my database, the status of a lead is not a 1 to 1 relation. That is because I want to have a historic list of all the statuses which a Lead has had.
That means that when a Lead is created, the first LeadStatus is created with the status of 'new' and the current date.
If a salesman comes in, he can change the status of the lead, but this DOES NOT update the previous LeadStatus, instead it creates a new related LeadStatus with the current date and status of 'open'.
This way I can see that a Lead was created on 05/05/2018 and that it changed to the status 'open' on 07/05/2018.
Now I'm trying to write a query using eloquent, which only takes in count the LATEST status related to a Lead.
In the previous example, if I filter by Lead with status 'new', this Lead should not appear as it has a status of 'open' by now.
Hope this helps
Try this:
Lead::select('leads.*')
->join('lead_statuses', 'leads.id', 'lead_statuses.lead_id')
->where('lead_statuses.status', $search['status'])
->where('created_at', function($query) {
$query->selectRaw('max(created_at)')
->from('lead_statuses')
->whereColumn('lead_id', 'leads.id');
})->get();
A solution using the primary key (by Borjante):
$builder->where('lead_statuses.id', function($query) {
$query->select('id')
->from('lead_statuses')
->whereColumn('lead_id', 'leads.id')
->orderBy('created_at', 'desc')
->limit(1);
});
I had this same problem and posted my solution here but I think it's worth re-posting as it improves on the re-usability. It's the same idea as the accepted answer but avoids using joins, which can cause issues if you want to eager load relations or use it in a scope.
The first step involves adding a macro to the query Builder in the AppServiceProvider.
use Illuminate\Database\Query\Builder;
Builder::macro('whereLatestRelation', function ($table, $parentRelatedColumn)
{
return $this->where($table . '.id', function ($sub) use ($table, $parentRelatedColumn) {
$sub->select('id')
->from($table . ' AS other')
->whereColumn('other.' . $parentRelatedColumn, $table . '.' . $parentRelatedColumn)
->latest()
->take(1);
});
});
This basically makes the sub-query part of the accepted answer more generic, allowing you to specify the join table and the column they join on. It also uses the latest() function to avoid referencing the created_at column directly. It assumes the other column is an 'id' column, so it can be improved further. To use this you'd then be able to do:
$status = $search['status'];
Lead::whereHas('statuses', function ($q) use ($status) {
$q->where('status', $userId)
->whereLatestRelation((new LeadStatus)->getTable(), 'lead_id');
});
It's the same logic as the accepted answer, but a bit easier to re-use. It will, however, be a little slower, but that should be worth the re-usability.
If I understand it correctly you need / want to get all Leads with a specific status.
So you probably should do something like this:
// In your Modal
public function getLeadById($statusId)
{
return Lead::where('status', $statusId)->get();
// you could of course extend this and do something like this:
// return Lead::where('status', $statusId)->limit()....->get();
}
Basically I am doing a where and returning every lead with a specific id.
You can then use this function in your controller like this:
Lead::getLeadById(1)

Retrieve data from one table and order by related table column using Laravel eloquent

I have two models Category and Transaction the table structures are like this
Categories:
id,category_name,..
and
Transactions:
id,category_id,amount..
The relation is
Category hasMany transactions
public function transactions()
{
return $this->hasMany('App\Transaction');
}
Transactions blongsTo Category
public function category()
{
return $this->belongsTo('App\Category', 'category_id');
}
I want to retrieve all data of transaction table which are sorted by category name.
Most importantly I want to get it using the eloquent method.
I have tried eager load which I think doesn't work on the belongsTo relationship.
Here is the code I have used for the eager load.
$transactions = Transaction::with(['category' => function ($query) {
$query->orderBy('category_name', 'asc');
}])->paginate(10);
So far I can achieve this by writing a query like below, but I'd like to use the eloquent method.
$transactions = Transaction::select(DB::raw('transactions.*'))
->leftJoin(DB::raw('(select id,category_name from categories) as categories'), 'categories.id', '=', 'transactions.category_id')
->orderBy('category_name', 'asc')
->paginate(10);
It'd be nice if someone can help me with this. Thank You.
Note: I am using Laravel 5.1
You have to provide the method name that defines the relationship, in your case this is category.
$transactions = Transaction::all()->with('category')->group_by('category.name')->get();
$transactions = Transaction::with('categories')->group_by('category.name')->get();
$cs = Course::where(['courses.active' => 1])
->whereHas('course_dates', function ($join) use ($now) {
$join->where('course_dates.start_date_time', '>', $now);
$join->orderBy('course_dates.start_date_time', 'asc');
})
->whereHas('category', function ($join) use ($cat_slug) {
$join->where('categories.url_slug', '=', $cat_slug);
})
->whereHas('language', function ($join) use ($cat_slug) {
$join->where('languages.string_id', '=', strtoupper(App::getLocale()));
})
->with(['course_dates' => function($q){
$q->orderBy('course_dates.start_date_time', 'desc');
}])
->join('course_dates' ,'course_dates.course_id', '=', 'courses.id')
->orderby('course_dates.start_date_time')
->limit(7)
->get();
To return Eloquent models ordered by related model (hasMany) column, I had to join the tables and then orderBy, still get the models, but correctly ordered by course_date.start_date_time.
Laravel 5.7, I don't think there is a cleaner solution (at least after few hours of tinkering and searching the web).