laravel convert to string mysql - php

I have this code written in using the laravel and I wonder how to write it in pure SQL without using laravel, as would be?
Route::get('popular', function(){
$media = Media::where('active', '=', '1')->join('media_likes', 'media.id', '=', 'media_likes.media_id')->groupBy('media_likes.media_id')->orderBy(DB::raw('COUNT(media_likes.id)'), 'DESC')->select('media.*')->paginate(30);
$data = array(
'media' => $media,
'categories' => Category::all(),
'pages' => Page::all(),
'settings' => Setting::first(),
);
return View::make('Theme::home', $data);
});

Using toSql method
Laravel Query builder has a helpful method called toSql which is handy to see what the final SQL query looks like.
Now, when you call the paginate method, you'll get a Paginator and you won't be able to call the toSql method.
Deconstructing paginate
When you use paginate, Laravel will make the following query for each $page:
// Let's simplify the query for now
Media::skip(($page - 1) * $perPage)->take($perPage);
Knowing that, you can use the query builder's method toSql and you'll see the actual sql string.
Supossing $page=3, $perPage=30, and that the name of the table is media, you'll get something like this:
Media::skip(2 * 30)->take(30)->toSql();
select * from media limit 30 offset 60
Now, for your actual query, you can use the following to see the resulting SQL string for the page 3 (as an example):
Media::where('active', '=', '1')
->join('media_likes', 'media.id', '=', 'media_likes.media_id')
->groupBy('media_likes.media_id')
->orderBy(DB::raw('COUNT(media_likes.id)'), 'DESC')
->select('media.*')
->skip(2 * 30)
->take(30)
->toSql();
Listening For Query Events
Alternatively, you can set an event listener in your AppServiceProvider, and log each SQL query the application executes.
public function boot()
{
\DB::listen(function ($query) {
\Log::debug($query->sql);
\Log::debug($query->bindings);
\Log::debug($query->time);
});
}

$media = Media::where('active', '=', '1')->join('media_likes', 'media.id', '=', 'media_likes.media_id')->groupBy('media_likes.media_id')->orderBy(DB::raw('COUNT(media_likes.id)'), 'DESC')->select('media.*')->paginate(30);
Something like this:
SELECT m.*
FROM
media m
JOIN
media_likes ml
ON
ml.media_id = m.id
GROUP BY
ml.media_id
ORDER BY
COUNT(ml.id) DESC

Related

Need help for my sql query to make use of AS operator [duplicate]

Lets say we are using Laravel's query builder:
$users = DB::table('really_long_table_name')
->select('really_long_table_name.id')
->get();
I'm looking for an equivalent to this SQL:
really_long_table_name AS short_name
This would be especially helpful when I have to type a lot of selects and wheres (or typically I include the alias in the column alias of the select as well, and it gets used in the result array). Without any table aliases there is a lot more typing for me and everything becomes a lot less readable. Can't find the answer in the laravel docs, any ideas?
Laravel supports aliases on tables and columns with AS. Try
$users = DB::table('really_long_table_name AS t')
->select('t.id AS uid')
->get();
Let's see it in action with an awesome tinker tool
$ php artisan tinker
[1] > Schema::create('really_long_table_name', function($table) {$table->increments('id');});
// NULL
[2] > DB::table('really_long_table_name')->insert(['id' => null]);
// true
[3] > DB::table('really_long_table_name AS t')->select('t.id AS uid')->get();
// array(
// 0 => object(stdClass)(
// 'uid' => '1'
// )
// )
To use aliases on eloquent models modify your code like this:
Item
::from( 'items as items_alias' )
->join( 'attachments as att', DB::raw( 'att.item_id' ), '=', DB::raw( 'items_alias.id' ) )
->select( DB::raw( 'items_alias.*' ) )
->get();
This will automatically add table prefix to table names and returns an instance of Items model. not a bare query result.
Adding DB::raw prevents laravel from adding table prefixes to aliases.
Here is how one can do it. I will give an example with joining so that it becomes super clear to someone.
$products = DB::table('products AS pr')
->leftJoin('product_families AS pf', 'pf.id', '=', 'pr.product_family_id')
->select('pr.id as id', 'pf.name as product_family_name', 'pf.id as product_family_id')
->orderBy('pr.id', 'desc')
->get();
Hope this helps.
To use in Eloquent.
Add on top of your model
protected $table = 'table_name as alias'
//table_name should be exact as in your database
..then use in your query like
ModelName::query()->select(alias.id, alias.name)
You can use less code, writing this:
$users = DB::table('really_long_table_name')
->get(array('really_long_table_name.field_very_long_name as short_name'));
And of course if you want to select more fields, just write a "," and add more:
$users = DB::table('really_long_table_name')
->get(array('really_long_table_name.field_very_long_name as short_name', 'really_long_table_name.another_field as other', 'and_another'));
This is very practical when you use a joins complex query
I have tried all these options and none works for me. Then I had found something in the Laravel documentation that really works.
You could try this:
DB::table('table_one as t1')
->select(
't1.field_id as id','t2.field_on_t2 as field'
)->join('table_two as t2', function ($join) {
$join->on('t1.field_id ', '=', 't2.field_id');
})->get()
Also note that you can pass an alias as the second parameter of the table method when using the DB facade:
$users = DB::table('really_long_table_name', 'short_name')
->select('short_name.id')
->get();
Not sure if this feature came with a specific version of Laravel or if it has always been baked in.
Same as AMIB answer, for soft delete error "Unknown column 'table_alias.deleted_at'",
just add ->withTrashed() then handle it yourself like ->whereRaw('items_alias.deleted_at IS NULL')
In the latest version of Laravel 9, you can use alias name for column as:
$events = Booking::whereBetween('sessionDateTime', [$today, $nextMonth])->get(['bookings.sessionDateTime as start']); // start is an alias here

WhereNotExists Laravel Eloquent

Little bit of trouble with the eloquent framework for laravel.
I need to replicate a query like this :
SELECT *
FROM RepairJob
WHERE NOT EXISTS (SELECT repair_job_id
FROM DismissedRequest
WHERE RepairJob.id = DismissedRequest.repair_job_id);
Right now I have
$repairJobs = RepairJob::with('repairJobPhoto', 'city', 'vehicle')->where('active', '=', 'Y')->whereNotExists('id', [DismissedRequest::all('repair_job_id')])->get();
Anyone an idea? I need to get all the repairjobs where there is no record for in the dismissed requests table
I get this error when using the query above
Argument 1 passed to Illuminate\Database\Query\Builder::whereNotExists() must be an instance of Closure, string given
Try this:
$repairJobs = RepairJob::with('repairJobPhoto', 'city', 'vehicle')
->where('active', '=', 'Y')
->whereNotExists(function($query)
{
$query->select(DB::raw(1))
->from('DismissedRequest')
->whereRaw('RepairJob.id = DismissedRequest.id');
})->get();
Try doesntHave() method. Assuming 'dismissedRequests' as relation name in RepairJob model.
$jobs = RepairJob::with('repairJobPhoto', 'city', 'vehicle')
->where('active', 'Y')->doesntHave('dismissedRequests')->get();

Different values when use DB::raw() in second param on where()

I have next query in Laravel Eloquent:
$buildings = Building::select('buildings.*')->join(
DB::raw('('.
(
IngameBuilding::select('buildings.building_id', 'buildings.level')
->join('buildings', 'buildings.id', '=', 'ingame_buildings.building_id')
->toSql()
).
') as `added_buildings`'), 'added_buildings.building_id', '=', 'buildings.building_id')
->where('buildings.level', '>', 'added_buildings.level')
->get();
This query returns all allowed rows from base, but one row more. When I added DB::raw() in where() return values is valid.
Good-working code:
$buildings = Building::select('buildings.*')->join(
DB::raw('('.
(
IngameBuilding::select('buildings.building_id', 'buildings.level')
->join('buildings', 'buildings.id', '=', 'ingame_buildings.building_id')
->toSql()
).
') as `added_buildings`'), 'added_buildings.building_id', '=', 'buildings.building_id')
->where('buildings.level', '>', DB::raw('`added_buildings`.`level`'))
->get();
Why first code workig, hmm.. Wrong?
I'm not a big fan of Laravel at all.
I've got only small experience with this framework but i'm almost sure that where function accepts only a 'constant' values to be checked against.
If you'll get an output of this query using toSQL method on the query object you will see that eloquent will convert it as something like:
(...) where buildings.level > 'added_buildings.level'
so the condition checks if the buildings.level (whatever the type is)
is greater than the given string and not the column value.
Using the DB::raw you're getting the proper sql as the eloquent won't parse/convert it.
You would need to use whereRaw method I suppose.
http://laravel.com/docs/4.2/queries#introduction

Laravel using UNION in query builder

I have an SQL query that works fine and I'm trying to convert into fluent::
SELECT DISTINCT tags.tag
FROM tags, items
WHERE tags.taggable_type = 'Item'
AND items.item_list_id = '1'
UNION
SELECT DISTINCT tags.tag
FROM tags, itemlists
WHERE tags.taggable_type = 'ItemList'
AND itemlists.id = '1'
This is what I have so far in fluent, it all seems right as far as I can tell from the docs and the individual queries both work on their own, it's just when I UNION them it throws an error:
$itemTags = Tag::join('items', 'items.id', '=', 'tags.taggable_id')
->select('tags.tag')
->distinct()
->where('tags.taggable_type', '=', 'Item')
->where('items.item_list_id', '=', $itemList->id);
$itemListTags = Tag::join('itemlists', 'itemlists.id', '=', 'tags.taggable_id')
->select('tags.tag')
->distinct()
->where('tags.taggable_type', '=', 'ItemList')
->where('itemlists.id', '=', $itemList->id);
// the var_dump below shows the expected results for the individual queries
// var_dump($itemTags->lists('tag'), $itemListTags->lists('tag')); exit;
return $itemTags
->union($itemListTags)
->get();
I get the following error when I run it (I've also swapped from Ardent back to Eloquent on the model in case that made a difference - it doesn't):
Argument 1 passed to Illuminate\Database\Query\Builder::mergeBindings() must be an instance of Illuminate\Database\Query\Builder, instance of LaravelBook\Ardent\Builder given, called in path/to/root\vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php on line 898 and defined
Looks like your models are using Ardent, not Eloquent:
...instance of LaravelBook\Ardent\Builder given, ...
And probably this might be a problem on Ardent, not Laravel.
Open an issue here: https://github.com/laravelbook/ardent.
EDIT:
Try to change use QueryBuilder instead of Eloquent:
Use this for QueryBuilder:
DB::table('tags')->
Instead of the Eloquent way:
Tag::
I know you mentioned wanting to use the query builder, but for complex queries that the builder might throw fits on, you can directly access the PDO object:
$pdo = DB::connection()->getPdo();

How to alias a table in Laravel Eloquent queries (or using Query Builder)?

Lets say we are using Laravel's query builder:
$users = DB::table('really_long_table_name')
->select('really_long_table_name.id')
->get();
I'm looking for an equivalent to this SQL:
really_long_table_name AS short_name
This would be especially helpful when I have to type a lot of selects and wheres (or typically I include the alias in the column alias of the select as well, and it gets used in the result array). Without any table aliases there is a lot more typing for me and everything becomes a lot less readable. Can't find the answer in the laravel docs, any ideas?
Laravel supports aliases on tables and columns with AS. Try
$users = DB::table('really_long_table_name AS t')
->select('t.id AS uid')
->get();
Let's see it in action with an awesome tinker tool
$ php artisan tinker
[1] > Schema::create('really_long_table_name', function($table) {$table->increments('id');});
// NULL
[2] > DB::table('really_long_table_name')->insert(['id' => null]);
// true
[3] > DB::table('really_long_table_name AS t')->select('t.id AS uid')->get();
// array(
// 0 => object(stdClass)(
// 'uid' => '1'
// )
// )
To use aliases on eloquent models modify your code like this:
Item
::from( 'items as items_alias' )
->join( 'attachments as att', DB::raw( 'att.item_id' ), '=', DB::raw( 'items_alias.id' ) )
->select( DB::raw( 'items_alias.*' ) )
->get();
This will automatically add table prefix to table names and returns an instance of Items model. not a bare query result.
Adding DB::raw prevents laravel from adding table prefixes to aliases.
Here is how one can do it. I will give an example with joining so that it becomes super clear to someone.
$products = DB::table('products AS pr')
->leftJoin('product_families AS pf', 'pf.id', '=', 'pr.product_family_id')
->select('pr.id as id', 'pf.name as product_family_name', 'pf.id as product_family_id')
->orderBy('pr.id', 'desc')
->get();
Hope this helps.
To use in Eloquent.
Add on top of your model
protected $table = 'table_name as alias'
//table_name should be exact as in your database
..then use in your query like
ModelName::query()->select(alias.id, alias.name)
You can use less code, writing this:
$users = DB::table('really_long_table_name')
->get(array('really_long_table_name.field_very_long_name as short_name'));
And of course if you want to select more fields, just write a "," and add more:
$users = DB::table('really_long_table_name')
->get(array('really_long_table_name.field_very_long_name as short_name', 'really_long_table_name.another_field as other', 'and_another'));
This is very practical when you use a joins complex query
I have tried all these options and none works for me. Then I had found something in the Laravel documentation that really works.
You could try this:
DB::table('table_one as t1')
->select(
't1.field_id as id','t2.field_on_t2 as field'
)->join('table_two as t2', function ($join) {
$join->on('t1.field_id ', '=', 't2.field_id');
})->get()
Also note that you can pass an alias as the second parameter of the table method when using the DB facade:
$users = DB::table('really_long_table_name', 'short_name')
->select('short_name.id')
->get();
Not sure if this feature came with a specific version of Laravel or if it has always been baked in.
Same as AMIB answer, for soft delete error "Unknown column 'table_alias.deleted_at'",
just add ->withTrashed() then handle it yourself like ->whereRaw('items_alias.deleted_at IS NULL')
In the latest version of Laravel 9, you can use alias name for column as:
$events = Booking::whereBetween('sessionDateTime', [$today, $nextMonth])->get(['bookings.sessionDateTime as start']); // start is an alias here

Categories