Laravel orderByRaw is removing results from union query - php

I am running this query in a project where I am having "meta_competitions" and "primary_events" that is going to merge together into a result where they do not overlap by primary_event_meta_competitions having the primary_event_id of the current primary_event.
Everything is working as expected in the query itself, we are getting the results we want. But when we add the orderByRaw() everything except one result is removed of the meta_competitions.
I have tried running the query I get when i am running "->toSql()" instead of ->get() of the query in pure sql and there everything works as expected.
$metaCompetitions = DB::table('meta_competitions')
->select('meta_competitions.name as name', 'sports.name as sport', 'meta_competitions.id', 'meta_competitions.country')
->where('meta_competitions.name', 'LIKE', "%{$string}%")
->whereIn('meta_competitions.sport_id', [1, 3, 4, 9])
->join('sports', 'sports.id', '=', 'meta_competitions.sport_id');
$leagues = DB::table('primary_events')
->select('primary_events.name as name', 'sports.name as sport', 'primary_events.id', 'primary_events.country')
->where('primary_events.name', 'LIKE', "%{$string}%")
->whereIn('primary_events.sport_id', [1, 3, 4, 9])
->whereNull('primary_event_meta_competitions.primary_event_id')
->leftJoin('primary_event_meta_competitions', 'primary_event_meta_competitions.primary_event_id', '=', 'primary_events.id')
->leftJoin('sports', 'sports.id', '=', 'primary_events.sport_id')
->union($metaCompetitions)
->orderByRaw(
'CASE
WHEN name = ? THEN 1
WHEN name LIKE ? THEN 2
WHEN name LIKE ? THEN 4
ELSE 3
END', [$string, "{$string}%", "%{$string}"]
)
->get();
dd($leagues);
The query that I get from ->toSql() and that works for me is the following:
(select `primary_events`.`name` as `name`, `sports`.`name` as `sport`, `primary_events`.`id`, `primary_events`.`country` from `primary_events`
left join `primary_event_meta_competitions` on `primary_event_meta_competitions`.`primary_event_id` = `primary_events`.`id`
left join `sports` on `sports`.`id` = `primary_events`.`sport_id`
where `primary_events`.`name` LIKE '%Allsvenskan%' and `primary_events`.`sport_id` in (1, 3, 4, 9) and `primary_event_meta_competitions`.`primary_event_id` is null)
union (select `meta_competitions`.`name` as `name`, `sports`.`name` as `sport`, `meta_competitions`.`id`, `meta_competitions`.`country` from `meta_competitions`
inner join `sports` on `sports`.`id` = `meta_competitions`.`sport_id`
where `meta_competitions`.`name` LIKE '%Allsvenskan%' and `meta_competitions`.`sport_id` in (1, 3, 4, 9))
order by CASE
WHEN name = 'Allsvenskan' THEN 1
WHEN name LIKE 'Allsvenskan%' THEN 2
WHEN name LIKE '%Allsvenskan' THEN 4
ELSE 3
END
My tables looks like:
meta_competitions
id:name:sport_id:country
primary_events
id:name:sport_id:country
sports
id:name
primary_event_meta_competitions
primary_event_id:meta_competition_id

This was kind of an odd issue. When I did not orderByRaw but used a selectRaw to a custom column and sorted that column everything worked as expected.
Why is this different at all?
$metaCompetitions = DB::table('meta_competitions')
->select('meta_competitions.name as name', 'sports.name as sport', 'meta_competitions.id', 'meta_competitions.country')
->selectRaw('CASE
WHEN meta_competitions.name = ? THEN 1
WHEN meta_competitions.name LIKE ? THEN 2
WHEN meta_competitions.name LIKE ? THEN 4
ELSE 3
END AS order_col', [$string, "$string%", "%$string"] )
->selectRaw("'meta_competition' AS type")
->where('meta_competitions.name', 'LIKE', "%{$string}%")
->whereIn('meta_competitions.sport_id', [1, 3, 4, 9])
->join('sports', 'sports.id', '=', 'meta_competitions.sport_id');
$leagues = DB::table('primary_events')
->select('primary_events.name as name', 'sports.name as sport', 'primary_events.id', 'primary_events.country')
->selectRaw('CASE
WHEN primary_events.name = ? THEN 1
WHEN primary_events.name LIKE ? THEN 2
WHEN primary_events.name LIKE ? THEN 4
ELSE 3
END AS order_col', [$string, "$string%", "%$string"] )
->selectRaw("'league' AS type")
->where('primary_events.name', 'LIKE', "%{$string}%")
->whereIn('primary_events.sport_id', [1, 3, 4, 9])
->whereNull('primary_event_meta_competitions.primary_event_id')
->leftJoin('primary_event_meta_competitions', 'primary_event_meta_competitions.primary_event_id', '=', 'primary_events.id')
->leftJoin('sports', 'sports.id', '=', 'primary_events.sport_id')
->union($metaCompetitions)
->orderBy('order_col')
->get();

Related

Laravel - Query Buider - SQL fields using LPAD statement

I'm cannot retry this query, in QueryBuilder:
select id, lpad(number, 12, 0), lpad(int, 2, 0) from users;
How I can, in the example not function...
DB::table('users') ->select('id', 'lpad(number, 12, 0)', 'lpad(int, 2, 0)' ->get();
You need to use selectRaw.
DB::table('users')
->selectRaw('id, lpad(number, 12, 0), lpad(int, 2, 0)')
->get();
https://laravel.com/docs/8.x/queries#selectraw

MySQL/Eloquent force id by left join even if null

I have this query wrote in Eloquent :
return TypeModel::with(['apt' => function($q) use ($id){
$q->leftJoin('build_apt', function($join) use($id){
$join->on('build_apt.id_apt', '=', 'apt.id_apt');
$join->on('build_apt.id_build', '=', DB::raw($id->id_build));
})
}])
->get()
->toJson();
Equivalent SQL :
SELECT *
FROM `apt`
LEFT JOIN `build_apt`
ON `build_apt`.`id_apt` = `apt`.`id_apt`
AND `build_apt`.`id_build` = 1
WHERE `apt`.`id_typeapt` in (1, 2, 3, 4, 5)
I have the result I need except one thing, the id given is null :
[
{"id_typeapt":1,"apt":[
{"id_apt":null,"image_apt":"apt_1.png"},
{"id_aptitude":null,"image_apt":"apt_2.png"}
]
]
How can I force it to look for the id from the table "apt" and not giving me "null" as a result?
Thanks you!
EDIT : Where clause is coming from the with
public function apt(){
return $this->hasMany(AptModel::class, 'id_typeapt', 'id_typeapt');
}
EDIT2 :
id_apt was crushed by the other id_apt with a simple rename I could retrieve the id :
return TypeModel::with(['apt' => function($q) use ($id){
$q->leftJoin('build_apt', function($join) use($id){
$join->on('build_apt.id_apt', '=', 'apt.id_apt');
$join->on('build_apt.id_build', '=', DB::raw($id->id_build));
})
}])->select(DB::raw("*, apt.id_apt as id_apt);
}])
You are using LEFT JOIN, which is what you want, however you have conditions on the joined table in the WHERE clause. This actually turns your LEFT JOIN to an INNER JOIN, since unmatched records will be filtered out by the WHERE clause.
You would need to tweak your Eloquent code in order to generate the following SQL query :
SELECT *
FROM `apt`
LEFT JOIN `build_apt`
ON `build_apt`.`id_apt` = `apt`.`id_apt`
AND `build_apt`.`id_build` = 1
AND `apt`.`id_typeapt` in (1, 2, 3, 4, 5)

How can I convert this inner join mysql query to Laravel's fluent?

I have this inner join query that I want to covert to Laravel's fluent. The things it is partially working. I'm able to get the results but those operators that mysql supports like and I'm finding it difficult to apply it to my fluent query.
mysql query:
SELECT students.surname as Name, subjects.name as Subject, grades.name as Class, terms.name as Term, score as Score
from scores
inner join students
on students.id = scores.student_id
and scores.student_id = 1
inner join subjects
on subjects.id = scores.subject_id
and scores.student_id = 1
inner join grades
on grades.id = scores.grade_id
and scores.student_id = 1
inner join terms
on terms.id = scores.term_id
and scores.student_id = 1
where scores.term_id = 1 or scores.term_id = 2 or scores.term_id = 3;
laravel query:
$scores = \DB::table('scores')
->join('students', 'students.id', '=', 'scores.student_id')
->join('subjects', 'subjects.id', '=', 'scores.subject_id')
->join('grades', 'grades.id', '=', 'scores.grade_id')
->join('terms', 'terms.id', '=', 'scores.term_id')
->select('students.surname', 'subjects.name', 'grades.name', 'terms.name', 'score')
->where('students.id', '=', '1', 'and', 'scores.term_id', '=', '1', 'or', 'scores.term_id', '=', '2', 'or', 'scores.term_id', '=', '3')
->get();
The problem I now have is in my where clause. It's seems like the and operator is being overlook and returning results that are not to be in the result set.
this is the result set when I dd it:
4th Period shouldn't be in the result set as it is term 4. Note term 1 is 1st Period, term 2 is 2nd Period and term 3 is 3rd Period
Use whereBetween to achive your desired result :
$scores = \DB::table('scores')
->join('students', 'students.id', '=', 'scores.student_id')
->join('subjects', 'subjects.id', '=', 'scores.subject_id')
->join('grades', 'grades.id', '=', 'scores.grade_id')
->join('terms', 'terms.id', '=', 'scores.term_id')
->select('students.surname', 'subjects.name', 'grades.name', 'terms.name', 'score')
->where('students.id', 1)
->whereBetween('scores.term_id', [1, 3])
->get();
Check out https://laravel.com/docs/5.4/queries#where-clauses for more documentation but you can clean up that where clause you made (you can change the documentation to represent the version of laravel you are using in the upper right hand corner).
instead of
->where('students.id', '=', '1', 'and', 'scores.term_id', '=', '1', 'or', 'scores.term_id', '=', '2', 'or', 'scores.term_id', '=', '3')
Do:
->where('students.id', 1)
->where('scores.term_id', 1)
->orWhere('scores.term_id', 2)
->orWhere('scores.term_id', 3)

Laravel Eloquent Query Not Working

$demos = Demo::whereIn('store_id', [1,2,4], function($query){
$query->where('status', 1);
})->paginate(10);
I know that this thats not working, But how can I work with this logic..?
[Select * from 'demos' where store_id in 1,2,4 and status = 1 ]
If I understand correctly you need something like this.
$demos = Demo::whereIn('store_id', [1, 2, 4])->where('status', 1)->paginate(10);
Chained "where" Eloquent methods == "AND" database query conditions.
Sometimes, it is better not use ORM`ish approach.
They say, old plain SQL is your best friend. So.
$data = \DB::select(
\DB::raw("SELECT * FROM `demos` WHERE `store_id` IN (:id1, :id2, :id3)"), array( ':id1' => 1, ':id2' => 2, ':id3' => 3 )
);
Or, if you have unknown count of store_id entries, you could:
$ids = array(1, 2, 3, 4, ...); // looks like unknown ammount of entries
$data = \DB::select(
\DB::raw("SELECT * FROM `demos` WHERE `store_id` IN (".rtrim(str_repeat('?,', count($ids)),',').")"), $ids
);

laravel: multiple select query

I understand that to do a select query is
$bearLawly = Bear::where('name', '=', 'Lawly')->first();
but how to I do a select query such as
SELECT * FROM bear where name = 'abc' AND age => '5' AND title = 'kid' ORDER BY name LIMIT 5, 10
Thanks!
You may try this:
$bearLawly = Bear::where('name', 'abc') // By default = will be used, so optional
->where('age', '>=', '5')
->where('title', 'kid')
->orderBy('name') // or orderBy('name', 'desc') for reverse
->take(5)->skip(10)->get();
According to following query:
SELECT * FROM bear where name = 'abc' AND age => '5' AND title = 'kid' ORDER BY name LIMIT 5, 10
Just chain them:
$bearLawly = Bear::where('name', 'Lawly')->where('age', '5')->first();

Categories