I have a query that retrieves data from 5 tables using joins. While I obtain the right result, it's quite slow.
The tables:
data_bundles
vendors
ussd_strings
products users
data_bundles_category
How can I refactor this?
Also, the setup does not use models.
$data_bundle_transaction = DB::table('data_bundles')
->select('*','data_bundles.phone_number as data_bundles_phone_number')
->join('vendors','vendors.vendor_id','=','data_bundles.vendor_id')
->join('ussd_strings','data_bundles.product_id','=','ussd_strings.product_id')
->join('products','data_bundles.product_id','=','products.product_id')
->join('users','users.user_id','=','data_bundles.user_id')
->leftJoin('data_bundle_category', 'data_bundle_category.product_id', '=', 'data_bundles.product_id')
->where('data_bundles.status',0)
->where('data_bundles.network','like', '%' . $request->network.'%')
->where('data_bundle_category.data_category', '=', $request->type)->first();
You could try using joins with multiple conditions, this way you will join less data and query will be faster
$data_bundle_transaction = DB::table('data_bundles')
->select('*','data_bundles.phone_number as data_bundles_phone_number')
->join('vendors','vendors.vendor_id','=','data_bundles.vendor_id')
->join('ussd_strings','data_bundles.product_id','=','ussd_strings.product_id')
->join('products','data_bundles.product_id','=','products.product_id')
->join('users','users.user_id','=','data_bundles.user_id')
->leftJoin('data_bundle_category', function() use ($request){
$join->on('data_bundle_category.product_id', '=', 'data_bundles.product_id');
$join->on('data_bundle_category.data_category', '=', $request->type);
})
->where('data_bundles.status',0)
->where('data_bundles.network','like', '%' . $request->network.'%')
->first();
Related
please someone can optimize this query according to Laravel query builder with some help of joins
Product::select(DB::raw('
products.*
,(select name from users where users.id=products.user_id) as user_name
'))
->where(function ($query) use ($searchKey) {
if (trim($searchKey) != '') {
$query->where('name', 'like', '%' . trim($searchKey) . '%');
}
})
->orderBy($orderBy,$orderType)
->paginate(10)
Maybe something like this:
//Start your query as usual, but just join the user data in. Do not use paginate function yet as this will trigger the query to execute.
$productQuery = Product
::selectRaw('products.*, users.name as user_name')
->join('users', 'users.id', 'products.user_id')
->orderBy($orderBy, $orderType);
//Check (for each param) if you want to add where clause
//You dont need to nest the where function, unless you have more filters, and need to group statements together
if(!empty(trim($searchKey))) {
$productQuery->where('name', 'like', '%' . trim($searchKey) . '%');
}
//Execute query
$products = $productQuery->paginate(10);
Note that the query builder only touches the db with specific functions like chunk, get, first or paginate(there are more). When building the query, you have full freedom of adding filters/ordering/grouping untill you execute the query.
I hope it helps, please let me know if it worked for you.
I have some records, i want to get records from them where item is not between given time range, here is my code that i already tried but no success
$other_hour_trade = DB::table('finaltrade')
->join('exchanges', 'finaltrade.exchange_id', '=', 'exchanges.id')
->select('finaltrade.*')
->where('finaltrade.user_id', $user_id)
->whereNotBetween('finaltrade.created_at', [DB::raw('exchanges.start_time'), DB::raw("ADDTIME(exchanges.start_time, '01:00:00')")])
->whereNotBetween('finaltrade.created_at', [DB::raw('exchanges.close_time'), DB::raw("SUBTIME(exchanges.close_time, '01:00:00')")])
->get();
'finaltrade.created_at' is a datetime field and
'exchanges.start_time' and 'exchanges.close_time' is a only time field
I have join two tables to get results
I don't know how to make this work directly using whereNotBetween, but since you're already trying to resort to some raw SQL in your current code, why not just use whereRaw instead:
$other_hour_trade = DB::table('finaltrade')
->join('exchanges', 'finaltrade.exchange_id', '=', 'exchanges.id')
->select('finaltrade.*')
->where('finaltrade.user_id', $user_id)
->whereRaw("finaltrade.created_at NOT BETWEEN exchanges.start_time AND ADDTIME(exchanges.start_time, '01:00:00')")
->whereRaw("finaltrade.created_at NOT BETWEEN exchanges.close_time AND SUBTIME(exchanges.close_time, '01:00:00')")
->get();
I have this sql (MariaDB) query, it works ok:
SELECT
admin_combustibles.nombre,
admin_combustibles.id_combustible,
admin_combustible_unidades.nombre AS unidades,
admin_tipo_combustibles.nombre AS tipo_combustible,
admin_indice_combustibles.valor_combustible
FROM
admin_combustibles
INNER JOIN admin_combustible_unidades ON admin_combustibles.combustible_unidades_id = admin_combustible_unidades.id_combustible_unidad
INNER JOIN admin_tipo_combustibles ON admin_combustibles.tipo_combustible_id = admin_tipo_combustibles.id_tipo_combustible
LEFT JOIN admin_indice_combustibles ON admin_combustibles.id_combustible = admin_indice_combustibles.combustible_id
AND admin_indice_combustibles.anio = 1992
AND admin_indice_combustibles.mes = 6
ORDER BY
admin_combustibles.nombre
But when I try to make it through Laravel, I have some error because Laravel put some on the number 1992, in that way the query doesn't work.
Plus, I don't know how to do the AND on Laravel, I only have orOn but it doesn't work:
$datos = AdminCombustible::select([
'admin_combustibles.nombre',
'admin_combustibles.id_combustible',
'admin_combustible_unidades.nombre AS unidades',
'admin_tipo_combustibles.nombre AS tipo_combustible',
'admin_indice_combustibles.valor_combustible'])
->join('admin_combustible_unidades', 'admin_combustibles.combustible_unidades_id', '=', 'admin_combustible_unidades.id_combustible_unidad')
->join('admin_tipo_combustibles', 'admin_combustibles.tipo_combustible_id', '=', 'admin_tipo_combustibles.id_tipo_combustible')
->leftJoin('admin_indice_combustibles', function ($join) {
$join->on('admin_indice_combustibles.combustible_id', '=', 'admin_combustibles.id_combustible')->orOn('admin_indice_combustibles.anio', '=', 1992);
})
->get();
dd($datos);
I got an sql syntax error.
Any help on how to make that query with query builder of Laravel? (I put the entire query as DB::raw and it works, but I don't want to use raw() )
I think there might be two problems here. Since you are using and in your original query, you might be needing to use or instead of orOn on your join.
Also you will need to use DB::raw() on the parameters, otherwise Laravel will consider them columns....
$join->on('admin_indice_combustibles.combustible_id', '=', 'admin_combustibles.id_combustible')->on('admin_indice_combustibles.anio', '=', DB::raw('1992'));
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.
I am having problems building a query which delimit the number of lawyers by branch of law in one particular territory(province) of the country.
I have four tables, one with the branchlaws, one for users, one where lawyers add branches where the practice law and one for territories.
I am able to summarize all this information with the following query:
$lawyersbyprovince = DB::table('branchlawsubareas')
->leftJoin('lawyerbranches', function($join) {
$join->on( 'branchlawsubareas.id', '=', 'lawyerbranches.subarea_id');
})
->leftJoin('users', function($join) {
$join->on( 'lawyerbranches.user_id', '=', 'users.id');
})
->leftJoin('states', function($join) {
$join->on('users.working_province', '=', 'states.id_state');
})
->leftJoin('branchlaws', 'branchlawsubareas.area_id', '=', 'branchlaws.id')
->select('branchlawsubareas.name as subarea',
DB::raw('count(lawyerbranches.subarea_id) as total'),
'branchlawsubareas.id'
)
->where('states.id_state','=', $province)
->groupBy('branchlawsubareas.id')
->get();
This query returns the number of lawyers per branch of law but it does not delimit by province. I have spent enough time trying things but obviously I missing something.
Any help will be much appreciated.
Try not to join instead the states of leftjoin.
$lawyersbyprovince = DB::table('branchlawsubareas')
->leftJoin('lawyerbranches', 'branchlawsubareas.id', '=', 'lawyerbranches.subarea_id')
->leftJoin('users', 'lawyerbranches.user_id', '=', 'users.id')
->leftJoin('branchlaws', 'branchlawsubareas.area_id', '=', 'branchlaws.id')
->join('states', 'users.working_province', '=', 'states.id_state')
->where('states.id_state','=', $province)
->select('branchlawsubareas.name as subarea',
DB::raw('count(lawyerbranches.subarea_id) as total'),
'branchlawsubareas.id'
)
->groupBy('branchlawsubareas.id')
->get();
Now if this does not work, you have another way. Remove where() clause and change your select like this
...
->select(''branchlawsubareas.id', 'states.id as state_id')
...
This will return a collection with ALL the data. Then you can manipulate that collection like this
$newCollection = $resultFromQuery->where('state_id', $province);
$newCollection->count(); //number of laywer in that state
I hope this helps, or simply gives you a hint.