Convert SQL query into Laravel query builder - laravel

I need to convert this query into laravel query builder
select * from employee where(( age = 25 and salary = 20000) or (age =30 and salary = 30000))

If you want to group where clauses you can nest them inside closures:
DB::table('employee')
->where(function ($query) {
$query->where('age', 25)->where('salary', 20000);
})
->orWHere(function ($query) {
$query->where('age', 30)->where('salary', 30000);
})
->get();
For more information have a look at Parameter Grouping in the documentation.

Can you try this,
$data = Model::where([["age", "25"],["salary", "20000"]])
->orWhere([["age", "30"],["salary", "30000"]])
->get();

Related

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

DB::raw convert to query builder

Can you help me to convert the Raw part of my query to use query builder?
I am stuck at joining it all together:
$profile = UserProfiles::select('id')->where('alias', $profileAlias)->first();
$dbRawMessagesCount = '
(SELECT COUNT(pm.id)
FROM profile_messages pm
WHERE pm.to_profile_id='.$profile->id.'
AND pm.from_profile_id=profile_friend.id
AND pm.is_read=0) AS messages_count
';
$friends = ProfileFriend::select('profile_friend.*', DB::raw($dbRawMessagesCount))
->with('friendProfile')
->whereHas('ownerProfile', function ($query) use ($profile) {
return $query->where('id', $profile->id);
})
->orderBy('messages_count')
->paginate();
You can rewrite this into one query if ProfileFriend has a relation already set up to ProfileMessages using withCount() in the query.
$friends = ProfileFriend::with('friendProfile')
->withCount(['profileMessages' => function($q) use($profile){
$q->where('to_profile_id', $profile->id)->where('is_read', 0);
// No longer need 'from_profile_id' as it is already querying the relationship
}])
->whereHas('ownerProfile', function ($query) use ($profile) {
return $query->where('id', $profile->id);
})
->paginate();
Now if you dd($friends->first()) you will notice it has a field called profileMessages_count that gives you a count of what I'm assuming is unread messages.

Laravel 5 nested or and clause within another and clause

I want to run this query but with laravel query builder I'm not getting the exactly results using orWhere and where clause
SELECT * FROM lectures WHERE school=6 AND ( (period=3 AND class_section=3) OR (period=4 AND teacher=17) )
so how can I do it with laravel query builder can anyone help me out?
You need to use Parameter Grouping to translate your query to query builder form
DB::table('lectures)
->where('school', '=', 6)
->where(function ($query) {
$query->where(function ($query) {
$query->where('period', '=', 3)
->where('class_section', '=', 3)
})->orWhere(function ($query) {
$query->where('period', '=', 4)
->where('class_section', '=', 17)
});
})
->get();

Why query returns empty collection?

I have the following query was built by Laravel:
$res = Announcement::whereExists(function ($query) {
$query->select(DB::raw(1))
->from('announcement_category')->join('user_category', 'user_category.category_id', '=', 'announcement_category.category_id')
->where('user_category.user_id', '=', 1)
->where('announcement_category.announcement_id', '=', 'announcements.id');
});
dd($res->get());
The code above gives me empty collection: dd($res->get());.
The plain SQL code of this query is:
select * from `announcements` where exists (select 1 from
`announcement_category` inner join `user_category` on
`user_category`.`category_id` = `announcement_category`.`category_id` where `user_category`.`user_id` = 1
and `announcement_category`.`announcement_id` = announcements.id)
and `announcements`.`deleted_at` is null
If execute this directly in MySQL, I get two result rows.
But why dd($res->get()); retuns me empty?
I don't think there is a whereExists in eloquent model... try this:
$res = DB::table('announcement')->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('announcement_category')->join('user_category', 'user_category.category_id', '=', 'announcement_category.category_id')
->where('user_category.user_id', '=', 1)
->where('announcement_category.announcement_id', '=', 'announcements.id');
})->get();

A JOIN With Additional Conditions Using Query Builder or Eloquent

I'm trying to add a condition using a JOIN query with Laravel Query Builder.
<?php
$results = DB::select('
SELECT DISTINCT
*
FROM
rooms
LEFT JOIN bookings
ON rooms.id = bookings.room_type_id
AND ( bookings.arrival between ? and ?
OR bookings.departure between ? and ? )
WHERE
bookings.room_type_id IS NULL
LIMIT 20',
array('2012-05-01', '2012-05-10', '2012-05-01', '2012-05-10')
);
I know I can use Raw Expressions but then there will be SQL injection points. I've tried the following with Query Builder but the generated query (and obviously, query results) aren't what I intended:
$results = DB::table('rooms')
->distinct()
->leftJoin('bookings', function ($join) {
$join->on('rooms.id', '=', 'bookings.room_type_id');
})
->whereBetween('arrival', array('2012-05-01', '2012-05-10'))
->whereBetween('departure', array('2012-05-01', '2012-05-10'))
->where('bookings.room_type_id', '=', null)
->get();
This is the generated query by Laravel:
select distinct * from `room_type_info`
left join `bookings`
on `room_type_info`.`id` = `bookings`.`room_type_id`
where `arrival` between ? and ?
and `departure` between ? and ?
and `bookings`.`room_type_id` is null
As you can see, the query output doesn't have the structure (especially under JOIN scope). Is it possible to add additional conditions under the JOIN?
How can I build the same query using Laravel's Query Builder (if possible) Is it better to use Eloquent, or should stay with DB::select?
$results = DB::table('rooms')
->distinct()
->leftJoin('bookings', function($join)
{
$join->on('rooms.id', '=', 'bookings.room_type_id');
$join->on('arrival','>=',DB::raw("'2012-05-01'"));
$join->on('arrival','<=',DB::raw("'2012-05-10'"));
$join->on('departure','>=',DB::raw("'2012-05-01'"));
$join->on('departure','<=',DB::raw("'2012-05-10'"));
})
->where('bookings.room_type_id', '=', NULL)
->get();
Not quite sure if the between clause can be added to the join in laravel.
Notes:
DB::raw() instructs Laravel not to put back quotes.
By passing a closure to join methods you can add more join conditions to it, on() will add AND condition and orOn() will add OR condition.
If you have some params, you can do this.
$results = DB::table('rooms')
->distinct()
->leftJoin('bookings', function($join) use ($param1, $param2)
{
$join->on('rooms.id', '=', 'bookings.room_type_id');
$join->on('arrival','=',DB::raw("'".$param1."'"));
$join->on('arrival','=',DB::raw("'".$param2."'"));
})
->where('bookings.room_type_id', '=', NULL)
->get();
and then return your query
return $results;
You can replicate those brackets in the left join:
LEFT JOIN bookings
ON rooms.id = bookings.room_type_id
AND ( bookings.arrival between ? and ?
OR bookings.departure between ? and ? )
is
->leftJoin('bookings', function($join){
$join->on('rooms.id', '=', 'bookings.room_type_id');
$join->on(DB::raw('( bookings.arrival between ? and ? OR bookings.departure between ? and ? )'), DB::raw(''), DB::raw(''));
})
You'll then have to set the bindings later using "setBindings" as described in this SO post:
How to bind parameters to a raw DB query in Laravel that's used on a model?
It's not pretty but it works.
The sql query sample like this
LEFT JOIN bookings
ON rooms.id = bookings.room_type_id
AND (bookings.arrival = ?
OR bookings.departure = ?)
Laravel join with multiple conditions
->leftJoin('bookings', function($join) use ($param1, $param2) {
$join->on('rooms.id', '=', 'bookings.room_type_id');
$join->on(function($query) use ($param1, $param2) {
$query->on('bookings.arrival', '=', $param1);
$query->orOn('departure', '=',$param2);
});
})
I am using laravel5.2 and we can add joins with different options, you can modify as per your requirement.
Option 1:
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')->orOn(...);//you add more joins here
})// and you add more joins here
->get();
Option 2:
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')// you may add more joins
->select('users.*', 'contacts.phone', 'orders.price')
->get();
option 3:
$users = DB::table('users')
->leftJoin('posts', 'users.id', '=', 'posts.user_id')
->leftJoin('...', '...', '...', '...')// you may add more joins
->get();
For conditional params we can use where,
$results = DB::table('rooms')
->distinct()
->leftJoin('bookings', function($join) use ($param)
{
$join->on('rooms.id', '=', 'bookings.room_type_id')
->where('arrival','=', $param);
})
->where('bookings.room_type_id', '=', NULL)
->get();
There's a difference between the raw queries and standard selects (between the DB::raw and DB::select methods).
You can do what you want using a DB::select and simply dropping in the ? placeholder much like you do with prepared statements (it's actually what it's doing).
A small example:
$results = DB::select('SELECT * FROM user WHERE username=?', ['jason']);
The second parameter is an array of values that will be used to replace the placeholders in the query from left to right.
My five cents for scheme LEFT JOIN ON (.. or ..) and (.. or ..) and ..
->join('checks','checks.id','check_id')
->leftJoin('schema_risks', function (JoinClause $join) use($order_type_id, $check_group_id, $filial_id){
$join->on(function($join){
$join->on('schema_risks.check_method_id','=', 'check_id')
->orWhereNull('schema_risks.check_method_id')
;
})
->on(function($join) use ($order_type_id) {
$join->where('schema_risks.order_type_id', $order_type_id)
->orWhereNull('schema_risks.order_type_id')
;
})
->on(function($join) use ($check_group_id) {
$join->where('schema_risks.check_group_id', $check_group_id)
->orWhereNull('schema_risks.check_group_id')
;
})
->on(function($join) use($filial_id){
$join->whereNull('schema_risks.filial_id');
if ($filial_id){
$join->orWhere('schema_risks.filial_id', $filial_id);
}
})
->on(function($join){
$join->whereNull('schema_risks.check_risk_level_id')
->orWhere('schema_risks.check_risk_level_id', '>' , CheckRiskLevel::CRL_NORMALLLY );
})
;
})

Resources