Joins in laravel 5.3 in simple and Eloquent - mysql

I want to add some extra filter in my left join but I don't know how so kindly help me.And also tell me how can make this query in Eloquent. My query is given below:
select * from `users`
join `halls` on `halls`.`user_id` = `users`.`id`
left join `bookings` on `bookings`.`hall_id` = `halls`.`id` AND month(`bookings`.`date`) = 2 and day(`bookings`.`date`) = 4 and year(`bookings`.`date`) = 2017
join `user_role` on `user_role`.`user_id` = `users`.`id`
join `roles` on `roles`.`id` = `user_role`.`role_id`
where
`roles`.`id` = 2 AND
(`bookings`.`id` is null OR `bookings`.`status` = 0 )
group by users.id
user and role has many to many relation, user and hall one to many and hall and bookings has also one to many relation
User Model Relation
/**
* Many-to-Many relations with Role.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function roles(){
return $this->belongsToMany(Role::class, 'user_role', 'user_id', 'role_id')->select('roles.name');
}
/**
* One-to-Many relations with halls.
*
* #return \Illuminate\Database\Eloquent\Relations\hasMany
*/
public function halls(){
return $this->hasMany(Hall::class);
}
Hall Model relation
public function user(){
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function bookings(){
return $this->hasMany(Booking::class);
}
Booking Model Realtion
public function hall(){
return $this->belongsTo(Hall::class)->distinct();
}

I dont know why you want to use group by without any aggregate function . Your ORM looks like below
Users::join('halls', 'users.id', '=', 'halls.user_id')
leftJoin('bookings', function($join){
$join->on('halls.id', '=', 'bookings.hall_id');
$join->on(DB::raw('month(`bookings`.`date`) = 2 and day(`bookings`.`date`) = 4 and year(`bookings`.`date`) = 2017'));
})
->join('user_role', 'users.id', '=', 'user_role.user_id')
->join('roles', 'roles.id', '=', 'user_role.role_id')
->whereRaw('where
`roles`.`id` = 2 AND
(`bookings`.`id` is null OR `bookings`.`status` = 0 )')->get();

Related

laravel eloquent query with relations

I'm trying to replace a mysql query with laravel eloquent. This is my structure.
Consumers Table
---------------
id, email, name
Transactions Table
-------------------
id, consumer_id, value, bonus_value
Output that I'm trying to achieve
id, email, name, total_value
1, abc#123.com, Al, 11000
2, abc2#123.com, Bl, 200000
This is what I have added in Consumer.php
/**
* Transactions Relationship
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function transactions(){
return $this->hasMany(Transaction::class, 'consumer_id');
}
And this is the query I've written so far.
$query = Consumer::query()
->join('consumer_transactions AS ct', function($q) {
$q->on('consumers.id', '=', 'ct.consumer_id')
->where('ct.status', 'processed')
->where('ct.approved', 1)
->select(DB::raw('SUM(ct.value + ct.bonus_value) AS total_points'))
;
})
->whereIn('consumers.id', $consumerIds)
->get()
;
It doesn't return total_points
Join Clause that passed to your join take Illuminate\Database\Query\JoinClause witch doesn't have a method called 'select'.
you select should be out of join clause.
$query = Consumer::query()
->join('consumer_transactions AS ct', function($q) {
$q->on('consumers.id', '=', 'ct.consumer_id')
->where('ct.status', 'processed')
->where('ct.approved', 1);
})
->select( ['consumers.*', DB::raw('SUM(ct.value + ct.bonus_value) AS total_points')])
->whereIn('consumers.id', $consumerIds)
->get();
I'm not fun of joining tables. That's why I can offer you a different approach.
$consumers = Consumer::whereIn('id', $consumerIds)
->with(['transactions' => function($query) {
$query
->where('startus', 'processed')
->where('approved', 1)
}])->get()
->map(function($item, $key) {
return $item->total_points = $item->transactions->value + $item->transactions->bonus_value
});

convert sql query (join) in laravel query builder

I want to do this request with laravel ( i have 3 tables users , userprojet and projets ) users hasmany projets and projet hasmany users that's why i do another table userprojet to join the two table
and now i try to extract the projet of a specific user with this request
select projets.*
from projets p
, userprojet up
, users u
where p.id= up.projet_id
and up.user_id = u.id
and user_id = 2;
I need help please.
You can try this:
$users = DB::table('projets')
->join('userprojet', 'projet_id.id', '=', 'userprojet.projet_id')
->join('userprojet', 'users.id', '=', 'userprojet.user_id')
->select('project.*')
->where('userprojet.user_id', 2)
->get();
References:
Laravel -> Queries -> Joins
You can also define many to many relationship in your models instead of writing queries every time
// User model
public function projets()
{
return $this->belongsToMany(Projet::class, 'userprojet');
}
// Projet model
public function users()
{
return $this->belongsToMany(User::class, 'userprojet');
}
// in controller
$user = User::first(); // for example
dd($user->projets);
// with eager loading
$user = User::with('projets')->first();
dd($user->projets);

Where not Exists en Laravel

Could anybody tell me what error I might have in my laravel query, basically what I want is to list the records of a table whose id is not related in another table. I did it in Mysql with this query: SELECT * FROM item WHERE NOT EXISTS (SELECT null FROM qualifications WHERE grades.item_id = item.id AND qualifications.user_id = 2);
but now I need to do this same query in laravel, I tried it this way:
codigo
and what I get is this syntax error that I do not know how to solve anymore:
error
I am very grateful to anyone who can tell me what I am doing wrong, or in what form I make that query in Laravel.
You can also rewrite your query as left join like
SELECT i.*
FROM item i
LEFT JOIN qualifications q ON q.item_id = i.id AND q.user_id = 2
WHERE q.item_id IS NULL
In query builder you can write it as
DB::table('item as i')
->select('i.*')
->leftJoin('qualifications as q', function ($join) use($user_id) {
$join->on('q.item_id', '=', 'i.id')
->on('q.user_id', '=', $user_id);
})
->whereNull('q.item_id')
->get();
Another approach which i suggest you to go with, is setup your relations and models and do it with eloquent way
class Item extends Model
{
public function qualifications()
{
return $this->hasMany(\App\Models\Qualification::class, 'item_id');
}
}
class Qualification extends Model
{
public function qualifications()
{
return $this->belongsTo(Item::class, 'item_id');
}
}
And then you can use Querying Relationship Absence
Item::whereDoesntHave('qualifications', function ($query) use($user_id) {
$query->where('user_id', '=', $user_id);
})->get();

Counting rows for the column in mysql

My problem is simple. I have two tables
transaction_bodies
------------------
body_id
full_name
and the other one is
transaction_accounts
--------------------
account_id
body_id
account_name
Relation is one to many. One body can have multiple accounts. I am trying to create a query that counts the accounts that bodies have.
I tried this
SELECT *
FROM
(
SELECT count(*) as trans, tb.full_name
FROM transaction_accounts ta
LEFT JOIN transaction_bodies tb
ON tb.body_id = ta.body_id
) as row;
But this doesn't give the right result. Can anyone help me out with this?
And if can provide how to write sub-queries in Laravel that would be a appreciated much.
Try this :
$result = DB::table('transaction_bodies')
->leftJoin('transaction_accounts as
ta','transaction_bodies.body_id','ta.body_id')
->select(DB::raw('count(ta.account_id) AS trans'),'transaction_bodies.full_name')
->groupBy('transaction_bodies.body_id')
->get();
You can do it with LEFT JOIN, e.g.:
SELECT tb.body_id, COUNT(ta.*)
FROM transaction_bodies LEFT JOIN transaction_accounts ta
ON tb.body_id = ta.body_id
GROUP BY tb.body_id;
With a simple LEFT JOIN you can achieve it like
SELECT tb.full_name, COUNT(account_id) as accounts
FROM transaction_bodies tb LEFT JOIN transaction_accounts ta
ON tb.body_id = ta.body_id
GROUP BY tb.body_id;
In Laravel you can do it like with model
$accounts = Transaction_body::leftJoin('transaction_accounts as ta','transaction_bodies.body_id','ta.body_id')->groupBy('transaction_bodies.body_id')->get();
without model
$accounts = DB::table('transaction_bodies')->leftJoin('transaction_accounts as ta','transaction_bodies.body_id','ta.body_id')->groupBy('transaction_bodies.body_id')->get();
/**
* Class Body
*/
class Body extends Model
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'transaction_bodies';
/**
* Get the accounts for the Transaction Body.
*/
public function accounts()
{
return $this->hasMany(Account::class);
}
}
/**
* Class Account
*/
class Account extends Model
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'transaction_accounts';
/**
* Get the body that owns the account.
*/
public function body()
{
return $this->belongsTo(Body::class);
}
}
//usage
$accounts = Body::find(1)->accounts;
https://laravel.com/docs/5.4/eloquent-relationships#one-to-many

How can I optimise this eloquent query to remove similar queries

An appointment can have many statuses, but the last created relation between appointment and status is the current status of the appointment. In my Appointment Datatable I want to display the related Agent, InstructionType, SignUpCustomer and the latest status. I want to paginate those records at 10 per page.
The relevant models are:
Appointment ( belongsTo agent, instruction_type and sign_up_customer, belongsToMany status)
Agent
InstructionType
SignUpCustomer
I have this query in my controller, which produces a result I send to Datatables.
$query = Appointment::with(['agent', 'instruction_type', 'sign_up_customer']);
$query->with(['statuses' => function ($query) {
$query->latest()->first();
}]);
$table = Datatables::of($query);
It is producing these two statements, the first one is fine, I don't need the last one. How can I optimise the query to remove that last statement?
select `statuses`.*, `appointment_status`.`appointment_id` as `pivot_appointment_id`, `appointment_status`.`status_id` as `pivot_status_id`, `appointment_status`.`created_at` as `pivot_created_at`, `appointment_status`.`updated_at` as `pivot_updated_at` from `statuses` inner join `appointment_status` on `statuses`.`id` = `appointment_status`.`status_id` where `appointment_status`.`appointment_id` in ('2') order by `created_at` desc limit 1
select `statuses`.*, `appointment_status`.`appointment_id` as `pivot_appointment_id`, `appointment_status`.`status_id` as `pivot_status_id`, `appointment_status`.`created_at` as `pivot_created_at`, `appointment_status`.`updated_at` as `pivot_updated_at`, `appointment_status`.`appointment_id` as `pivot_appointment_id`, `appointment_status`.`status_id` as `pivot_status_id`, `appointment_status`.`created_at` as `pivot_created_at`, `appointment_status`.`updated_at` as `pivot_updated_at` from `statuses` inner join `appointment_status` on `statuses`.`id` = `appointment_status`.`status_id` where `appointment_status`.`appointment_id` in ('2') order by `created_at` desc limit 1
I've also tried this:
Model:
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function statuses()
{
return $this->belongsToMany(Status::class, 'appointment_status')->withTimestamps();
}
public function latestStatus()
{
return $this->statuses()->latest()->first();
}
Controller:
$query = Appointment::with(['agent', 'instruction_type', 'sign_up_customer', 'latestStatus']);
$table = Datatables::of($query);
But i get this error: BadMethodCallException in Builder.php line 2445:
Call to undefined method Illuminate\Database\Query\Builder::addEagerConstraints()
Can you not do this using a local scope? https://laravel.com/docs/5.4/eloquent#local-scopes
public function scopeLatest($query)
{
return $query->orderBy('created_at', 'DESC')->offset(0)->limit(1);
}
I've not actually done this before, but I see no reason why it wouldn't work (I also have no idea how optimised the resulting query would be).