replace null value to N/A in left join using laravel eloquent - php

I know in sql using IFNULL I can replace null value. But i need this using laravel eloquent and also not use raw sql query in laravel eloquent.
public function testQuery() {
$dataList = SpeechModel::leftJoin('speech_subtitle', 'speech_title.speech_title_id', 'speech_subtitle.speech_subtitle_speech_id')->get();
return $dataList;
}
output
speech_title_id=null,speech_subtitle_id=null,speech_subtitle_text=null

You could use DB::raw() in the select() method:
$dataList = SpeechModel::select(
'*',
DB::raw('IFNULL(speech_subtitle.speech_subtitle_speech_id, "N/A") as subtitle')
)
->leftJoin(/*...*/)
->get();
This method lets you use Query Builder while using a raw statement in the SELECT. You could do this for every column.
But, honestly, if this is only about swapping null for N/A, you might consider doing it on the frontend instead.

Related

Laravel with where eloquent builder. How to use db records values inside subquery?

I want to use a record fields in laravel eloquent subquery
I tried this
$clients = Client::with(['records' => function (Builder $query) {
// how can i take a record fields there?
$record = $query->first();
$query->where('time', Carbon::now()->subMinutes(10 + $record->duration);
}])->where('profile_id', $profile->id)->get();
How can this be done?
Just use the use()
$clients = Client::with(['records' => function (Builder $query) use ($record) {
$query->where('time', Carbon::now()->subMinutes(10 + $record->duration);
}])->where('profile_id', $profile->id)->get();
Your query is wrong. It is not possible to use the $record or $query->first() inside the with method. You will only be able to use those data only after the final get(). Since Eloquent will first fetch the data matching the where conditions except the "with" method, and then it will generate a query to fetch the eager-loaded relationships using where in.
You can achieve this query using a raw query, or like the other answer you have to fetch the record first and use that in the callback.
$clients = Client::with([
'records' => function ($query) {
$query->whereRaw("`time` = (10 + `duration`)");
}
])
->where('profile_id', $profile->id)
->get();

Eloquent queries work separately but not together in a subquery

I'm trying to fetch some data with a subquery using Eloquent but dding returns nothing. Separately, this
$discountArticles = $discountTableItemIdIn
->where('recipient_type', '=', 'article')
->toArray();
or this
$discountArticles = $discountTableItemIdIn
->where('recipient_id', '=', $articleId)
->toArray();
work fine.
However when I try something like this, it fails (or rather, returns nothing):
$discountArticles = $discountTableItemIdIn->where(function ($subQuery) {
$subQuery
->where('recipient_type', '=', 'article')
->where('recipient_id', '=', $articleId);
})->toArray();
I know I can do separate queries on the same collection and do an array_merge but I'd like to get this way working instead. Not sure what's happening.
So $discountTableItemIdIn is a collection of the entire table? That means you're gonna need a different function, as the ->where() logic on a collection is different from how it functions on a builder (eloquent) instance.
Try using filter():
$discountArticles = $discountTableItemIdIn->filter(function ($item) use($articleId) {
return $item->recipient_type == "article" && $item->recipient_id == $articleId;
})->toArray();
What this will do is filter your $discountTableItemIdIn collection for records that have a type of article and a recipient_id of whatever $articleId contains, return a new collection and convert that to an array.
Just a note, this is quite inefficient; you should try to avoid loading the whole table into a collection and just query the table directly using the subquery logic in your question.

How to join two eloquent queries in laravel

This is my attempt:
$calendar = Calendar::leftJoin("class", "class.start_date", "<=", "calendar.date")
->leftJoin("student", "class.id", "student.class_id")
->where("student.id", $id)
->select("calendar.date");
$calendarQuery = $calendar->toSql();
$temperature = Temperature
::leftJoin("temperature_type", "temperature.temperature_type_id", "temperature_type.id")
->where("temperature.student_id", $id)
->select("temperature.student_id", "temperature.id", DB::raw("date(temperature.created_at) as date"), DB::raw("cast(temperature.created_at as time) as time"), "status", "temperature_type_id", "temperature_type.name as temperature_type", "temperature.temperature", "temperature.unit")
->orderby("temperature.id");
$temperatureQuery = $temperature->toSql();
$return['output'] = DB::table(DB::raw("($temperatureQuery) AS temp"))
->rightJoin(DB::raw("($calendarQuery) AS cal"),
function($join) use ($calendar){
$join->on("temp.date", "=" ,"cal.date")
->addBinding($calendar->getBindings());
})->get();
return $return;
I would like to joining this two eloquent queries.
I found this problem. Any suggestions?
Use fromSub():
DB::query()->fromSub($temperature, 'temp')
In Laravel 5.6.17 you can simplify the join with rightJoinSub():
->rightJoinSub($calendar, 'cal', 'temp.date', 'cal.date')
That occurs mainly because if you do dd($calendar), you will see that the toSql() method just translates the query into raw sql, without parameters. the $id will be '?' that's most likely it (as you can see on your bottom line of the error). The same applies to temperature
I don't advise converting to toSql() unless you really need to, you can do one single query to get the contents you're looking for

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

Categories