Laravel nested or with and in where condition - laravel

My Expected query is
select count(*) as aggregate from `books`
where (`books`.`is_deleted` = 0)
and `category_id` = '61'
and (`title` like '%問いかけの作法 チームの魅力と才能を引き出す技術%' or `title` like '%問イカケノ作法 チームノ魅力ト才能ヲ引キ出ス技術%' or `title` like '%問いかけの作法 ちーむの魅力と才能を引き出す技術%');
I have written my conditions like below ways
$queryCondition = $this::where(['books.is_deleted' => false]);
if( isset($queryString['category']) ){
$queryCondition->where('category_id',$queryString['category']);
}
if( isset($queryString['searchKey']) ){
$search = mb_convert_kana($queryString['searchKey'],"rns");
$kana = mb_convert_kana($search,"KVC");
$katakana = mb_convert_kana($search,"KVc");
$queryCondition->where('title','like','%'.$search.'%')
->orWhere('title','like','%'.$kana.'%')
->orWhere('title','like','%'.$katakana.'%')
;
}
I'm getting the output query like below
select count(*) as aggregate from `books`
where (`books`.`is_deleted` = 0)
and `category_id` = '61'
and `title` like '%問いかけの作法 チームの魅力と才能を引き出す技術%' or `title` like '%問イカケノ作法 チームノ魅力ト才能ヲ引キ出ス技術%' or `title` like '%問いかけの作法 ちーむの魅力と才能を引き出す技術%';
Without the () in last condition. How can I fix it ? Without this way has there any other ways to implement nested or in laravel ? Example
$query->where([
'OR' => [
[name LIKE' => '%'.$search.'%'],
[search LIKE' => '%'.$kana.'%'],
[search LIKE' => '%'.$katakana.'%']
]
]);

try this
->where(function ($query) {
$query->where('title','like','%問いかけの作法 チームの魅力と才能を引き出す技術%')
->orWhere('title','like','%問イカケノ作法 チームノ魅力ト才能ヲ引キ出ス技術%')
->orWhere('title','like','%問いかけの作法 ちーむの魅力と才能を引き出す技術%');
})
->get();
The closure will give you the () that you are seeking for.
Laravel documentation 9.x itself asks to add orwhere via above.
You should always group orWhere calls in order to avoid unexpected behavior when global scopes are applied.
From docs:
$users = DB::table('users')
->where('votes', '>', 100)
->orWhere(function($query) {
$query->where('name', 'Abigail')
->where('votes', '>', 50);
})
->get();
which will give you,
select * from users where votes > 100 or (name = 'Abigail' and votes > 50)

You should try whereRaw with raw query instead of orWhere
So, instead of this
->orWhere('title','like','%'.$kana.'%')
->orWhere('title','like','%'.$katakana.'%');
Do this
->whereRaw('title LIKE "%$kana%" OR title LIKE "%$katakana%" ');
From my experience, anytime i use orWhere(), it ignores all other conditions so i prefer to use whereRaw and it works fine for me without any issues

Related

How to transform this raw SQL query into Laravel Eloquent

This raw SQL query is returning the expected result on my SQL console. Would you please help me to transform it into a Laravel Eloquent query?
SELECT * FROM `my_services`
WHERE `user_id` = 1 and `financial_year` = '2021-2022'
AND (service_type = 'Return' OR service_type = 'Correction Return')
ORDER BY id DESC LIMIT 1,1;
I have tried to implement it like the following.
MyService::where([
'user_id' => $user->id,
'financial_year' => $request->financial_year,
'financial_year' => '2021-2022'
])
->orWhere(['service_type' => 'Return'])
->orWhere(['service_type' => 'Correction Return'])
->orderBy("id", "desc")
->offset(1)
->limit(1)
->get();
Try this query -
MyService::where('user_id', 1)->where('financial_year', '2021-2022')->where(function($q) {
$q->where('service_type', 'Return')->orWhere('service_type', 'Correction Return');
})->limit(1)->offset(1)->orderBy('id', 'DESC')->get();
From: https://laravel.com/docs/8.x/queries#limit-and-offset
Use ->skip(1) or ->offset(1) for offset
Use ->take(1) or ->limit(1) to limit count of returned results

Laravel Parameter Grouping (and/or where)

I upgraded Laravel to version 7, and when I do a query like this:
$users = User::where('name', '=', 'John')
->where(function ($query) {
$query->where('votes', '>', 100)
->orWhereNull('title');
})
->get();
it doesn't work as expected, and I got this error [SQL Server] Must specify table to select from
because the SQL should be like this:
select * from users where name = 'John' and (votes > 100 or title is null)
but when I debug the returned query it shows like this:
select * from users where name = 'John' and (select * votes > 100 or title is null) is null
The above query it just an example of my complex query, and I have a lot like this query in all of my project so I don't need a replacement, I just need to know how to fix it as it worked fine before upgrading
You can use whereRaw for the alternative method, for example
$users = Table::whereRaw(" name=? AND (votes=? OR title=?)", array(?,?,?))
$users = User::where('name', '=', 'John')
->where(function ($query) {
$query->from('users')
->where('votes', '>', 100)
->orWhereNull('title');
})
->get();

Laravel Eloquent select use group by

When I query the database I get the results I want.
$data['jobtypes'] = User::Select('jobtype_search', DB::raw('count(jobtype_search) as jobs'))->
Where('jobtype_search', '<>', '')
->GroupBy('jobtype_search')
->get();
However, when I do not want to keep calling the database for every query. Instead I call on the database once to get the chunk of data I need and then query off that.
$user = User::whereBetween('created_at', [$start_date, $end_date])->get();
When I try
$data['jobtype_search'] =$user->Select('jobtype_search', DB::raw('count(jobtype_search) as jobs'))->
Where('jobtype_search', '<>', '')
->GroupBy('jobtype_search')
->get();
I get a method select not found error.
What should I change so my query works?
The $user variable in your example is the result set (a Laravel collection) of the query, but you're trying to use it as a query.
This would work (another query):
$data['jobtype_search'] = User::whereBetween('created_at', [$start_date, $end_date])
->Select('jobtype_search', DB::raw('count(jobtype_search) as jobs'))
->Where('jobtype_search', '<>', '')
->GroupBy('jobtype_search')
->get();
Or if you want to do it on the result set, you could do it with the collection methods on the result set:
$data['jobtype_search'] = $user
->filter(function ($item) {
return $item->jobtype_search !== '';
})
->groupBy('jobtype_search')
->map(function ($item, $jobTypeSearch) {
return [
'jobtype_search' => $jobTypeSearch,
'jobs' => $item->count(),
];
})

How do I select an object from a collection where 1 of 2 columns equals a value?

I have the following which returns a collection of objects;
$cwGames = Schedule::where('date', '<', Carbon::now()->addDays(7))
->where('date', '>', Carbon::now()->addDays(1))->get();
Now I want to select from this collection only the object where $id is in col A or $id is in col B.
What's the best way to do this? Thanks.
Thanks to ExoticChimp for direction on the answer below. I added the use ($id) to get it to work. See edit here...
$cwGames = Schedule::where('date', '<', Carbon::now()->addDays(7))
->where('date', '>', Carbon::now()->addDays(1))
->where(function ($query) use ($id) {
// Replace col_A and col_B with your column names
$query->where('home_team_id', $id)
->orWhere('away_team_id', $id);
})->get();
The question is slightly ambiguous what you mean by col A and col B. However, if what you want is to add in an additional where clause which is effectively if colA or colB = $id, then the following should work (from the Laravel docs)
$cwGames = Schedule::where('date', '<', Carbon::now()->addDays(7))
->where('date', '>', Carbon::now()->addDays(1))
->where('name', '=', 'John')
->where(function ($query) {
// Replace col_A and col_B with your column names
$query->where('col_A', $id)
->orWhere('col_B', $id);
})
->get();
https://laravel.com/docs/master/queries#where-clauses
Laravel Collections has a lot of cool features that I think you should check on the official docs. In your case, the "filter" method is the best way to process the elements of your collection.
According to the official docs:
The filter method filters the collection by a given callback, keeping only those items that pass a given truth test
In your case:
$cwGames->filter(function($value, $key) {
// If your check returns true, the element will be kept in the collection
}
Check the docs here (filter method explained)

Codeigniter active records: like and where in SQL statement

I need to select several rows that respect these conditions:
date >= today
keyword present in fields 1, 2 or 3
i guess the SQL statement for this should be:
SELECT * FROM `events` WHERE date >= '2010-09-12' AND (field1 LIKE '%keyword%' OR field2 LIKE '%keyword%' OR field3 LIKE '%keyword%')
I am trying to write this using codeigniter's active records, but the the LIKE condition seems to override the date one.
$this->db->select('*');
$this->db->join('venues', 'events.venue = venue_id');
//first condition: date >= today
$this->db->where('date >=', date('Y-m-d'));
if ($keyword)
//if keyword is present, add this condition as well
{
$this->db->like('events.description', $keyword);
$this->db->or_like('band', $keyword);
$this->db->or_like('venues.venue', $keyword);
}
$this->db->order_by('date', 'ASC');
$this->db->order_by('events.priority', 'DESC');
$Q = $this->db->get('events');
I probably need to insert the LIKE statement inside a parentesis, but don't know how to do it.
I think you have to write the 'like'-part of your query this way:
$this->db->select('*');
$this->db->join('venues', 'events.venue = venue_id');
if ($keyword)
//if keyword is present, add this condition as well
{
$where = "( events.description LIKE '$keyword' OR band LIKE '$keyword' OR venues.venue LIKE '$keyword')";
$this->db->where($where);
}
//first condition: date >= today
$this->db->where('date >=', date('Y-m-d'));
$this->db->order_by('date', 'ASC');
$this->db->order_by('events.priority', 'DESC');
$Linkearray = array('page_content' => $search, 'page_title' => $search);
$this->db->like($Linkearray);
$this->db->where('page_online',1);
$this->db->where('page_site',$page_site);
// WHERE page_content LIKE '% my Text%'
// AND page_title LIKE '% my page title %'
// AND page_online = '1' and page_site ='29'
$array = array('title' => $match, 'page1' => $match, 'page2' => $match);
$this->db->like($array);
// WHERE title LIKE '%match%' AND page1 LIKE '%match%' AND page2 LIKE '%match%'

Resources