Eloquent select with join and not exists in raw statement - sql

I need to write select statement like that:
SELECT co.id FROM client_order co
INNER JOIN client_order_status cos ON cos.id = co.order_status_id AND cos.name IN ('for_shipping', 'to_be_shipped_later')
WHERE NOT EXISTS (SELECT 1 FROM dpackage dp WHERE dp.order_id = co.id AND dp.is_spec_label_generated = 1)
ORDER BY co.id
In Eloquent my expression looks like that:
$clientOrderEntities = ClientOrder::join('client_order_status', 'client_order_status.id', '=', 'order_status_id')
->whereIn('client_order_status.name', ['for_shipping', 'to_be_shipped_later'])
->whereNotExists(function($query) use($orderId) {
$query->select(DB::raw(1))
->from('dpackage')
->where([
['order_id', '=', $orderId]
['is_spec_label_generated', '=', 1]
]);
})->get();
I don't know how to pass orderId from first part of query into whereNotExists sub query
At the moment it looks:
$clientOrderEntities = ClientOrder::join('client_order_status', 'client_order_status.id', '=', 'order_status_id')
->whereIn('client_order_status.name', ['for_shipping', 'to_be_shipped_later'])
->whereNotExists(function($query) {
$query->select(DB::raw(1))
->from('dpackage')
->where([
['order_id', '=', 'client_order.id'],
['is_spec_label_generated', '=', 1]
]);
})
->select('client_order.*')
->get();
This query works:
$clientOrderEntities = ClientOrder::join('client_order_status', 'client_order_status.id', '=', 'order_status_id')
->whereIn('client_order_status.name', ['for_shipping', 'to_be_shipped_later'])
->whereRaw(' NOT EXISTS (SELECT 1 FROM dpackage dp WHERE dp.order_id = client_order.id AND dp.is_spec_label_generated = 1) ')
->select('client_order.*')
->get();
This query works too and is faster than eloquent statements, as #Newbie wrotes, but I don't know why his answer has been deleted:
$clientOrderEntities = DB::select('SELECT co.* FROM client_order co INNER JOIN client_order_status cos ON cos.id = co.order_status_id AND cos.name IN ("for_shipping", "to_be_shipped_later") WHERE NOT EXISTS (SELECT 1 FROM dpackage dp WHERE dp.order_id = co.id AND dp.is_spec_label_generated = 1) ');

Maybe defining name for the tables help you with this.
$clientOrderEntities = \DB::table('client_order as co')
->join('client_order_status as cos', 'cos.id', '=', 'co.order_status_id')
->whereIn('cos.name', ['for_shipping', 'to_be_shipped_later'])
->whereNotExists(function($query) {
$query->select(DB::raw(1))
->from('dpackage')
->where([
['order_id', '=', 'co.id'],
['is_spec_label_generated', '=', 1]
]);
})->get();

Related

laravel where raw automaticaly add is null

i have this code where i need to join transactions with transaction_sell_lines and transactions with purchase_lines. Then purchase_lines and transaction_sell_lines both has variation_id. I need to join those variation_id to variations table.
Transaction::leftJoin('purchase_lines as pl', 'transactions.id', '=', 'pl.transaction_id')
->leftJoin('transaction_sell_lines as sl', 'transactions.id', '=', 'sl.transaction_id')
->join('variations as v', function ($query) {
$query->where(DB::raw("CONCAT(COALESCE(sl.variation_id, ''), COALESCE(pl.variation_id, ''))"));
}, '=', 'v.id')
and when i checked the query using DB::enableQueryLog(); for some reason laravel automatically add is null even though i did not mention it anywhere. i could use whereNotNull() but the result still are not the same. the code could be seen below
from `transactions` left join `purchase_lines` as `pl` on `transactions`.`id` = `pl`.`transaction_id`
left join `transaction_sell_lines` as `sl` on `transactions`.`id` = `sl`.`transaction_id`
inner join `variations` as `v` on CONCAT(COALESCE(sl.variation_id, ''), COALESCE(pl.variation_id, '')) is null
how do i achieve this sql
from transactions LEFT JOIN purchase_lines as pl on pl.transaction_id = transactions.id
LEFT JOIN transaction_sell_lines as sl ON sl.transaction_id = transactions.id
LEFT JOIN variations as v on v.id = CONCAT(COALESCE(sl.variation_id,''),COALESCE(pl.variation_id,''))
I would suggest that you replace
$query->where(DB::raw("...")
with the whereRaw-function instead:
Transaction::leftJoin('purchase_lines as pl', 'transactions.id', '=', 'pl.transaction_id')
->leftJoin('transaction_sell_lines as sl', 'transactions.id', '=', 'sl.transaction_id')
->join('variations as v', function ($query) {
$query->whereRaw("CONCAT(COALESCE(sl.variation_id, ''), COALESCE(pl.variation_id, ''))");
}, '=', 'v.id')
you are using Advanced Join Clauses the wrong way ...
join with closure should take a Illuminate\Database\Query\JoinClause instance which allows you to specify constraints on the "join" clause, so the constraints should be in that function:
you can replace:
->join('variations as v', function ($query) {
$query->where(DB::raw("CONCAT(COALESCE(sl.variation_id, ''), COALESCE(pl.variation_id, ''))"));
}, '=', 'v.id')
with:
->join('variations as v', function ($query) {
$query->where(DB::raw("CONCAT(COALESCE(sl.variation_id, ''), COALESCE(pl.variation_id, ''))=v.id"));
})

Convert SQL with nested queries to Laravel Eloquent

I need to convert this query that I got from Access to an Laravel eloquent for my remake database project, and this is what i did but i haven't the same result with the origin sql thanks.
SELECT T_Sites.Code_Region, T_Sites.Nom_Site, T_CLM.N_CLM, T_Port.N_Port,
T_Vlan.IP_Vlan, T_Ref_Vlan.Id_Referentiel, T_Ref_Vlan.Nom_Vlan,
T_Vlan.Dt_Creat, T_Vlan.Id_Vlan, T_Vlan.IP_HSRP, T_Vlan.IP_SousReseaux,
T_CLM.Id_CLM, T_Vlan.Masque
FROM (T_CLM
INNER JOIN (
(T_Port INNER JOIN T_Vlan ON T_Port.Id_Port = T_Vlan.Id_Port)
LEFT JOIN T_Ref_Vlan ON T_Vlan.Id_Referentiel = T_Ref_Vlan.Id_Referentiel
)
ON T_CLM.Id_CLM = T_Port.Id_CLM)
INNER JOIN T_Sites ON T_CLM.Id_Site = T_Sites.Id_Site
ORDER BY T_CLM.Id_CLM DESC
WITH OWNERACCESS OPTION;
// what i did
$SuiviVlan = DB::table('T_CLM')
->join('T_Sites', 'T_CLM.Id_Site', '=', 'T_Sites.Id_Site')
->join('T_Port', 'T_CLM.Id_CLM' , '=', 'T_Port.Id_CLM')
->join('T_Vlan', 'T_Vlan.Id_Port', '=', 'T_Port.Id_Port')
->leftjoin('T_Ref_Vlan', 'T_Ref_Vlan.Id_Referentiel', '=', 'T_Vlan.Id_Referentiel')
->select('T_Sites.Code_Region','T_Sites.Nom_Site','T_CLM.N_CLM','T_Port.N_Port','T_Vlan.IP_Vlan',
'T_Ref_Vlan.Id_Referentiel', 'T_Ref_Vlan.Nom_Vlan', 'T_Vlan.Dt_Creat', 'T_Vlan.Id_Vlan', 'T_Vlan.IP_HSRP',
'T_Vlan.IP_SousReseaux', 'T_CLM.Id_CLM', 'T_Vlan.Masque')
->orderBy('T_CLM.Id_CLM', 'desc')
->get();
// It was the correct laravel eloquent , thanks btw for help.
$SuiviVlan = DB::table('T_CLM')
->join('T_Sites', 'T_CLM.Id_Site', '=', 'T_Sites.Id_Site')
->join('T_Port', 'T_CLM.Id_CLM' , '=', 'T_Port.Id_CLM')
->join('T_Vlan', 'T_Vlan.Id_Port', '=', 'T_Port.Id_Port')
->leftjoin('T_Ref_Vlan', 'T_Ref_Vlan.Id_Referentiel', '=', 'T_Vlan.Id_Referentiel')
->select('T_Sites.Code_Region','T_Sites.Nom_Site','T_CLM.N_CLM','T_Port.N_Port','T_Vlan.IP_Vlan',
'T_Ref_Vlan.Id_Referentiel', 'T_Ref_Vlan.Nom_Vlan', 'T_Vlan.Dt_Creat', 'T_Vlan.Id_Vlan', 'T_Vlan.IP_HSRP',
'T_Vlan.IP_SousReseaux', 'T_CLM.Id_CLM', 'T_Vlan.Masque')
->orderBy('T_CLM.Id_CLM', 'desc')
->get();

Laravel Query: implement Eloquent Scope for Query Builder

In the Laravel Query Builder I want to implement something like Scope in Eloquent.
Ref: Laravel Queries: Adding custom feature like Soft Deletes.
I have some complex queries (with joins and what not) but I want to be able to easily apply a WHERE condition that works as follows:
original:
Select * from t1 join t2 ... join t3 ... etc
Where t1.c1 = x OR t3.c4 like "%like"
wanted:
Select * from t1 join t2 ... join t3 ... etc
Where (t1.c1 = x OR t3.c4 like "%like") AND (t1.isTest = false AND t3.isTest = false)
I have written the following method:
public static function scopeNoTest($query, $tables=[false])
{
if (!is_array($tables)) $tables = [$tables];
foreach ($tables as $table)
{
$field = ($table) ? $table . '.isTest' : 'isTest';
$query = $query->where(function ($q) use ($query, $field)
{
$q->where($field, false)
->orWhereNull($field);
}
);
}
return $query;
}
It gets run like this:
$select = <parameter driven select statement>
$where[$role] = <array of different where condition based on passed in parameter?
$bindings = <query bindings based on passed in parameters>
$query = DB::table('Transactions AS trans')
->leftJoin('Buyers AS b', 'trans.ID', '=', 'b.Transactions_ID')
->leftJoin('Sellers AS s', 'trans.ID', '=', 's.Transactions_ID')
->leftJoin('Agents AS ba', 'trans.BuyersAgent_ID', '=', 'ba.ID')
->leftJoin('Agents AS sa', 'trans.SellersAgent_ID', '=', 'sa.ID')
->leftJoin('TransactionCoordinators AS btc', 'trans.BuyersTransactionCoordinators_ID', '=', 'btc.ID')
->leftJoin('TransactionCoordinators AS stc', 'trans.SellersTransactionCoordinators_ID', '=', 'stc.ID')
->leftJoin('lu_UserRoles AS lu_ur', 'trans.ClientRole', '=', 'lu_ur.Value')
->leftJoin('Properties AS p', 'trans.Properties_ID', '=', 'p.ID')
->selectRaw($select);
// ... Adds code to Only Select records with isTest NOT True
$query = Model_Parent::scopeNoTest($query, ['trans', 'ba', 'sa', ]);
$query->whereRaw($where[$role].$whereUser, $bindings)->distinct();
$transactions = $query->get();
The problem with this code is that it does not put the original [passed in] query in parentheses - so the query is wrong!.
The WHERE the code creates is:
where
(`trans`.`isTest` = 0 or `trans`.`isTest` is null)
and (`ba`.`isTest` = 0 or `ba`.`isTest` is null)
and (`sa`.`isTest` = 0 or `sa`.`isTest` is null)
and trans.BuyersTransactionCoordinators_ID = 1 OR trans.SellersTransactionCoordinators_ID = 1
OR trans.CreatedByUsers_ID = 1 OR trans.OwnedByUsers_ID = 1
And I want
where
(`trans`.`isTest` = 0 or `trans`.`isTest` is null)
and (`ba`.`isTest` = 0 or `ba`.`isTest` is null)
and (`sa`.`isTest` = 0 or `sa`.`isTest` is null)
and (trans.BuyersTransactionCoordinators_ID = 1 OR trans.SellersTransactionCoordinators_ID = 1
OR trans.CreatedByUsers_ID = 1 OR trans.OwnedByUsers_ID = 1)
Is there a way to do this ??
It looks like the following line is causing this:
$query->whereRaw($where[$role].$whereUser, $bindings)->distinct();
I think there are two ways to solve this:
// 1
->whereRaw('(' . $where[$role].$whereUser . ')', $bindings)->
// 2
->where(function ($query) use (...) {
$query->whereRaw(...);
})->

Query with select and count in laravel

I did this Query in SQL but I can't make it work in Eloquent.
Please help me.
SELECT
tags.desc,
COUNT(planificacion_info.id_area) as cantidad_intervenciones
FROM
tags
INNER JOIN planificacion_info ON planificacion_info.id_area = tags.id_tag
WHERE
tags.grupo = 'area' and tags.estado = true
GROUP BY
tags.desc
You can do it like this :
$result = \DB::table('tags')->selectRaw('tags.desc, COUNT(planificacion_info.id_area) as cantidad_intervenciones')
->join('planificacion_info', 'planificacion_info.id_area', '=', 'tags.id_tag')
->where('tags.grupo', 'area')
->whereRaw('tags.estado = true')
->groupBy('tags.desc')
->get();
which gives you this request :
SELECT
tags.desc,
COUNT(planificacion_info.id_area) AS cantidad_intervenciones
FROM
`tags`
INNER JOIN `planificacion_info` ON `planificacion_info`.`id_area` = `tags`.`id_tag`
WHERE
`tags`.`grupo` = 'area'
AND tags.estado = TRUE
GROUP BY
`tags`.`desc`
Would be something liek this
$tags= DB::table('tags')
->select('tags.desc',DB::raw("COUNT(planificacion_info.id_area) AS cantidad_intervenciones")
->innerJoin('planificacion_info','planificacion_info.id_area','=','tags.id_tag')
->where('tags.grupo','area')
->where('tags.estado',true)
->groupBy('tags.desc')
->get();

Eloquent 2 left join query

I would like to execute the following query using Laravel's eloquent query builder:
SELECT a.*, b.day, c.sex FROM hours as a
left join reserves as b
on a.id = b.hour_id and b.day = '2015-12-12'
left join doctors as c
on a.doctor_id = c.id
where a.doctor_id = 1;
I have tried the following:
Hour::leftJoin('reserves', function($join) {
$join->on('hours.id' , '=' , 'reserves.hour_id')
->where('reserves.day' , '=' , '2015-12-12');
})
->leftJoin('doctors', function($join) {
$join->on('hours.doctor_id', '=', 'doctors.id');
})
->where('hours.doctor_id', '=', $doctorId)
->get();
Unfortunately, I am not getting the same results.
Everything looks fine, however you miss selecting columns, after Hour:: you should add:
select('hours.*'.'reserves.day','doctors.sex')->
You could also make second join simpler and use aliases, so the final code could look like this:
Hour::select('hours.*'.'reserves.day','doctors.sex')
->from('hours AS a')
->leftJoin('reserves AS b', function($join) {
$join->on('a.id' , '=' , 'b.hour_id')
->where('b.day' , '2015-12-12');
})
->leftJoin('doctors AS c', 'a.doctor_id', '=', 'c.id')
->where('a.doctor_id', $doctorId)
->get();
Of course as $doctorId you should set 1 to get exact same result
you can use DB::raw :
Hour::select(DB::raw('hours.*'),reserves.day, c.doctors)
->leftJoin('reserves',DB::raw("hours.id = reserves.hour_id AND reserves.day='2015-12-12'") ,DB::raw(''), DB::raw(''))
->leftJoin('doctors','hours.doctor_id', '=', 'doctors.id')
->where('hours.doctor_id', '=', $doctorId)
->get()
the 2 empty DB::raw is because leftJoin expect 4 arguments(table,columnA,operator,columnB)