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.
Related
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();
This is the code that is already working in mysql database but I want to convert it into Laravel 5.6
SELECT *
FROM `listings`
WHERE (
country_id=1
AND (state=32 or city=8)
AND (listing_id LIKE "%6562%" OR title LIKE "%6562%"))
Supposedly you have a model called Listing which takes care of the listings table. You can write the query like this:
$listings = App\Listing::where('field1', 1)
->where(function ($query) {
$query->where('field2', 32);
$query->orWhere('field3', 8);
})
->where(function ($query) {
$query->where('field4', 'LIKE', '%6562%');
$query->orWhere('field5', 'LIKE', '%6562%');
})
->get();
The first parameter of the where method can be a callback which can achieve this type of grouping (field2=32 or field3=8)
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.
When using eloquent single table query like this
$query = Lists::query();
we can save in a temporary variable, but when we use multiple tables like this
Lists::with(['tags','keyproduct','productcatalog']);
why can't we save it in a variable like above? The reason I want to store in a temp variable like this is because I wanted conditional statement in the query like
if($something==true)
$query->where('type'=>'Paid')
Any idea how to break down the query using ::with()?
you can give condition in whrehas
$posts = List::whereHas('comments', function($q)
{
if($something==true){
$q->where('content', 'like', 'foo%');
}
})->get();
For more details http://laravel.com/docs/5.0/eloquent#querying-relations