Write Eloquent queries in raw mysql - mysql

I want to know how can I write These two Eloquent Queries into raw SQL? also Is there a way to convert the Eloquent series into raw SQL series so that I could use those?
public function items()
{
return $this->belongsToMany(Product::class, 'order_items', 'order_id', 'product_id')->withPivot('quantity', 'price');
}
public function user()
{
return $this->belongsTo(User::class);
}

If we talk about the first query used in the items method. After changing it into raw SQL it will become
DB::select('select `products`.*, `order_items`.`order_id` as `pivot_order_id`, `order_items`.`product_id` as `pivot_product_id`, `order_items`.`quantity` as `pivot_quantity`, `order_items`.`price` as `pivot_price` from `products` inner join `order_items` on `products`.`id` = `order_items`.`product_id` where `order_items`.`order_id` = `order_id`');
and the second query inside the user method will become
DB::select('select * from `users` where `users`.`id` = `id`');

Related

Need to convert a query into Eloquent Model laravel

I have a query of MySQL but I need to convert it into an eloquent model laravel 8. The query is given below,
$query = "SELECT group_id FROM `chat_histories` join chat_group on chat_group.id = chat_histories.group_id where chat_group.is_group = 1 and chat_histories.created_at BETWEEN '$startDate' and '$endDate' and chat_histories.deleted_at is null group by group_id";
$query = "select count(group_id) as total_chat_thread from ($query) total_chat";
DB::select($query);
So far i have done this,
ChatHistory::leftJoin('chat_group', 'chat_group.id', '=', 'chat_histories.group_id')
->selectRaw('count(*) as totals')
->where('chat_group.is_group', 1)
->whereBetween('chat_histories.created_at', [$startDate, $endDate])
->groupBy('chat_histories.group_id')
->count('totals');
But this returns a list, but I need that count of the list. That means it's showing 22 rows, I need that 22 as return.
My Model ChatHistory relation with ChatGroup
public function chatGroup() {
return $this->belongsTo(ChatGroup::class, 'group_id', 'id');
}
My Model ChatGroup relation with ChatHistory
public function chatHistory() {
return $this->hasMany(ChatHistory::class,'group_id','id');
}
Please help to convert it into an eloquent model query
Thanks in advance.
If you have the model Group with a relation history hasMany. it should be like this.
$groupCount = ChatGroup::whereHas('chatHistory', function ($historyQB) use($startDate,$endDate) {
$historyQB->whereBetween('created_at', [$startDate, $endDate])
->whereNull('deleted_at');
})->count();
You dont need the whereNull, if the model ChatHistory has softDelete enabled.
Maybe you should consider using Models, it would be much easier/cleaner
Something like that should work
DB::table('chat_histories')->select('group_id')->join('chat_group', 'chat_group.id', 'chat_histories.group_id')->where('chat_groups.is_group', 1)->whereBetween('chat_histories.created_at', $startDate, $endDate)->whereNull('chat_histories.deleted_at')->groupBy('group_id')->count();

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

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).

(Laravel) Join 3 or more tables using "Eloquent Relationships"

I'm trying to join 3 tables using eloquent relationships, but it doesn't give the expected results.
Shipment model
class Shipment extends Model
{
protected $table = 'ccctadm.Shipment';
public function customergroupcode()
{
return $this->hasMany(DocumentRuleSet::class,'customergroupcode','customergroupcode');
}
public function shipmentcategory()
{
return $this->hasMany(DocumentRuleSet::class,'shipmentcategory','shipmentcategory');
}
public function status()
{
return $this->hasMany(DocumentRuleSet::class,'status','status');
}
}
to get the data i'm using this code
$shipment_data = Shipment::With(['customergroupcode' , 'shipmentcategory','status'])->
Where('shipment_cycle','!=','closed')->get();
I'm trying to make it equivalent to this query
select B.rulesetname,B.icon ,COUNT(*)As Total from
[ccct].[ccctadm]. [Shipment] A INNER JOIN
[ccct].[ccctadm].[documentruleset] B
ON
A.customergroupcode = B.customergroupcode AND A.shipmentcategory =
B.shipmentcategory AND A.status = B.status INNER
JOIN [ccctadm].[shipassign] S ON A.id = S.shipmentid AND
A.shipment_cycle != 'closed' GROUP BY rulesetname,B.icon
The first query returns all the data in 3 tables, but when the second one returns Release only and this what I want
I only want the data that has relation among these three tables not everything
What I'm doing wrong ?
Use has() method. It limits the records based on existence of the relationship.
$shipment_data = Shipment::has('customergroupcode' , 'shipmentcategory','status')->
Where('shipment_cycle','!=','closed')->get();

Left Join from Select Zend Framework

How can I do a Query like this using the Zend framework
SELECT * FROM `productos` AS `p`
LEFT JOIN (SELECT SUM(cantidad) AS transferencias FROM transferencias WHERE upc = p`.`upc` and sucursal = 10)
AS `trans` ON trans.upc = p.upc AND trans.sucursal_clave_destino = 10
Thank you in advance.
You need to try this one.
I can't try it but the way of resolve it you can use from my query
$this->getAdapter()
->select()
->from(array('p' => 'productos'))
->joinLeft(array('trans' => $this->getAdapter()
->select()
->from('transferencias', 'SUM(cantidad)')
->where('upc IN (?)', $this->getAdapter()
->select()
->from('productos', 'upc')
)->where('sucursal = ?', 10)
), 'trans.upc = p.upc')
->where('trans.sucursal_clave_destino = ?', 10)
->query()
->fetchAll();
First of all, I'm afraid it's impossible for your query to run because the syntax is wrong. The correct way to write it is:
SELECT *, SUM(trans.cantidad) as cantidad
FROM productos AS p
LEFT JOIN transferencias AS trans
ON p.upc = trans.upc
WHERE trans.sucursal_clave_destino = 10 AND trans.sucursal = 10
First approach
I assume you have created your model in this manner: http://framework.zend.com/manual/1.12/en/learning.quickstart.create-model.html
For example, in your Default_Model_ProductosMapper:
function getXXXX(){
$select = "[THE ABOVE QUERY]";
$result = $this->getDbTable()->getAdapter()->fetchAll($select);
return $result;
}
This is the most basic approach.
Second approach
By using Zend_Db functions, which is like prepare statement in database concept. Only use it to increase safety if you are passing parameters from user input (see SQL injection), otherwise it's safe to use the first approach.
Still, in your mapper:
function getXXXX(){
$query = $this->getDbTable()->getAdapter()->select();
$query->from('productos', array());
$query->joinLeft('transferencias', 'productos.upc = transferencias.upc', array('SUM(trans.cantidad) as cantidad));
$query->where("trans.sucursal_clave_destino = 10");
$query->where("trans.sucursal = 10");
// get result
$stmt = $this->getDbTable()->getAdapter()->query($query);
$result = $stmt->fetchAll();
return $result;
}
Third approach
If you are using Database ORM like Doctrine2, you can also write SQL or DQL (Doctrine Query Language) queries, which syntax is highly similar with SQL queries but absolutely NOT the same mechanism. The document is here. This document covers both approaches above for DQL and also will tell you where to put them.