Make sql query simpler shorter ( Laravel ) - mysql

is there any way to make these queries shorter or simpler? or maybe get the result in 1 query rather than 3.??
any advise appreciated
$room_single = \DB::table('book_room')
->leftJoin('book_tour', 'book_room.bookingID', '=', 'book_tour.bookingID')
->where('tourdateID', '=', $id)
->where('roomtype','=',1)
->where('book_room.status','=',1)
->count();
$room_double = \DB::table('book_room')
->leftJoin('book_tour', 'book_room.bookingID', '=', 'book_tour.bookingID')
->where('tourdateID', '=', $id)
->where('roomtype','=',2)
->where('book_room.status','=',1)
->count();
$room_triple = \DB::table('book_room')
->leftJoin('book_tour', 'book_room.bookingID', '=', 'book_tour.bookingID')
->where('tourdateID', '=', $id)
->where('roomtype','=',3)
->where('book_room.status','=',1)
->count();
$total= $room_single+($room_double*2)+($room_triple*3) ;

In this case, since the roomtype column relates directly to how you would calculate the total you could just use sum instead of count:
$total = \DB::table('book_room')
->leftJoin('book_tour', 'book_room.bookingID', '=', 'book_tour.bookingID')
->where('tourdateID', '=', $id)
->where('book_room.status', '=', 1)
->sum('roomtype');
UPDATE
If you still need the count for each roomtype then you could do something like:
$query = \DB::table('book_room')
->leftJoin('book_tour', 'book_room.bookingID', '=', 'book_tour.bookingID')
->where('tourdateID', '=', $id)
->where('book_room.status', '=', 1);
$room_single = $query->newQuery()->where('roomtype', 1)->count();
$room_double = $query->newQuery()->where('roomtype', 2)->count();
$room_triple = $query->newQuery()->where('roomtype', 3)->count();
$total = $room_single + ($room_double * 2) + ($room_triple * 3);
Using newQuery means that you can reuse constraints without adding to the original.
Or if you don't want to make multiple queries and you want php to handle the counts
$rooms = \DB::table('book_room')
->select('roomtype')
->selectRaw('count(*) as room_count')
->leftJoin('book_tour', 'book_room.bookingID', '=', 'book_tour.bookingID')
->where('tourdateID', '=', $id)
->where('book_room.status', '=', 1)
->whereBetween('roomtype', [1, 3])//This is only needed if you have other room types
->groupBy('roomtype')
->orderBy('roomtype')
->get('roomtype');
list($room_single, $room_double, $room_triple) = $rooms->pluck('room_count')->toArray();
$total = $rooms->sum(function ($item) {
return $item->room_count * $item->roomtype;
});
Hope this helps!

I dont have enough contributions that is why am posting as answer.
try
GROUP BY roomtype
Then you will not need to change your roomtype.

You can do it in more simple way.
one is,
$query = \DB::table('book_room')
->leftJoin('book_tour', 'book_room.bookingID', '=', 'book_tour.bookingID')
->where('tourdateID', '=', $id)
->where('book_room.status','=',1);
$room_single = $query->where('roomtype','=',1)->count();
$room_double = $query->where('roomtype','=',2)->count();
$room_triple = $query->where('roomtype','=',3)->count();
And then add these as you want. This is just reducing your lines of code.
Another and better way is following.
$all_type = \DB::table('book_room')
->leftJoin('book_tour', 'book_room.bookingID', '=', 'book_tour.bookingID')
->where('tourdateID', '=', $id)
->where('book_room.status','=',1)
->select('roomtype',\DB::raw('COUNT(bookingID) as count'))
->groupBy('roomtype')
->get();
With this query you will get three count for each room type.
Hope you understand.

Related

Laravel where and orWhere function

I'm trying to count how many tickets our operators have closed in a week(and per day) I have these 2 queries
$closedWeek = Ticket::join('activity_log', 'activity_log.rel_id', '=', 'ticket.id')
->where([
['activity_log.created_at', '>', $fri],
['activity_log.user_id', '=', $id],
['activity_log.event_name', '=', 'ticket_closed'],
['number', 'like', 'SD%']
])->count();
$closedWeek2 = Ticket::join('activity_log', 'activity_log.rel_id', '=', 'ticket.id')
->where([
['activity_log.created_at', '>', $fri],
['activity_log.user_id', '=', $id],
['number', 'like', 'SD%'],
['activity_log.event_name', '=', 'ticket_department_updated']
])
->where(function($query) {
$query->where('activity_log.new_value', '=', 'closed Uninvoiced')
->orWhere('activity_log.new_value', '=', 'To Invoice')
->orWhere('activity_log.new_value', '=', 'closed Other')
->orWhere('activity_log.new_value', '=', 'closed Invoiced');
})->count();
$closedWeek = $closedWeek + $closedWeek2;
They are bringing back slightly bigger numbers than expected and I think some of them are duplicated. How could I put these into one query using where(function($query)) or do I have to use DB::raw instead? I can then count unique ids
You can use GroupBy(); with id,
Example:
$closedWeek = Ticket::join('activity_log', 'activity_log.rel_id', '=', 'ticket.id')
->where([
['activity_log.created_at', '>', $fri],
['activity_log.user_id', '=', $id],
['activity_log.event_name', '=', 'ticket_closed'],
['number', 'like', 'SD%']
])
->groupBy('ticket.id')
->count();
$closedWeek2 = Ticket::join('activity_log', 'activity_log.rel_id', '=', 'ticket.id')
->where([
['activity_log.created_at', '>', $fri],
['activity_log.user_id', '=', $id],
['number', 'like', 'SD%'],
['activity_log.event_name', '=', 'ticket_department_updated']
])
->whereIn('activity_log.new_value',
[ 'closed Uninvoiced',
'To Invoice',
'closed Other',
'closed Invoiced',
])
->groupBy('ticket.id')
->count();
$closedWeek = $closedWeek + $closedWeek2;
OBS:
You dont need '=', on equal wheres, example, where('colun', '=', 'abc'); you can change to where('colun', 'abc');
Please test and see if you have the expected result.
References:
How to get distinct values for non-key column fields in Laravel?

Join the same table with two different column laravel

I try these code in MySQl:
SELECT
A.*,
B.name,
C.name
FROM
eventlog_tbl as A
LEFT JOIN users B ON A.byuser=B.email
LEFT JOIN users C ON A.affectiveuser=C.email;
I try these in Laravel
return DB::table('eventlog_tbl')
->leftjoin('users', 'users.email', '=', 'eventlog_tbl.byuser')
->leftjoin('users', 'users.email', '=', 'eventlog_tbl.affectiveuser')
->select('eventlog_tbl.*','users.name','users.name')
->get();
How can i convert it to Laravel?
Try below code:
$res = DB::table('eventlog_tbl')
->leftjoin('users AS A', 'A.email', '=', 'eventlog_tbl.byuser')
->leftjoin('users AS B', 'B.email', '=', 'eventlog_tbl.affectiveuser')
->select('eventlog_tbl.*','A.name as byuser_name','B.name as affectiveuser_name')
->get();
print_r($res);
This is your query written using the Laravel query builder.
$events = DB::table('eventlog_tbl')
->select('eventlog_tbl.*', 'users_1.name', 'users_2.name')
->leftJoin('users AS users_1', 'users_1.email', '=', 'eventlog_tbl.byuser')
->leftJoin('users AS users_2', 'users_2.email', '=', 'eventlog_tbl.affectiveuser')
->get();
Edit:
$events = DB::table('eventlog_tbl')
->select('eventlog_tbl.*', 'users_1.name AS user_1', 'users_2.name AS user_2')
->leftJoin('users AS users_1', 'users_1.email', '=', 'eventlog_tbl.byuser')
->leftJoin('users AS users_2', 'users_2.email', '=', 'eventlog_tbl.affectiveuser')
->get();
The problem is that both name columns are called the same thing. As per the accepted answer, these will need to be aliased differently too.
Why don't you convert this to use relationships? I have probably got the relationships wrong, something like this:
class EventLog extends Model
{
public function byUser()
{
return $this->hasOne(User::class, 'byuser', 'id');
}
public function affectiveUser()
{
return $this->hasOne(User::class, 'affectiveuser', 'id');
}
}
And then
$event_log = EventLog::with(['byUser', 'affectiveUser')->all();
foreach ($event_log as $item) {
echo $item->byUser->email();
}

Comparing timestamp and Carbon::now()->toTimeString() without seconds

I am building a query which will be executed every minute when the daily_at time and the current time are equal. The daily_at variable is a timestamp of for example 10:05:33.
I want the where clause in the query to pass when the hour and minute are the same, but not the second else almost non will be executed. The where clause which I have now:
DB::table('restaurants')
->where('schedule', '=', $schedule)
->where('active', '=', 1)
->whereDate('start_at', '<=', Carbon::today())
->where('daily_at', '=', Carbon::now()->toTimeString())
.....
Could someone help me to adjust the where clause to ignore the seconds?
Try with:
DB::table('restaurants')
->where('schedule', '=', $schedule)
->where('active', '=', 1)
->whereDate('start_at', '<=', Carbon::today())
->where('daily_at', '=', Carbon::now()->format('H:i'))
One more way:
DB::table('restaurants')
->where('schedule', '=', $schedule)
->where('active', '=', 1)
->whereDate('start_at', '<=', Carbon::today())
->where('daily_at', '=', Carbon::createFromTime(Carbon::now()->hour,Carbon::now()->minute,00)->format('H:i:s'))
You can pass an extra argument to set timezone:
Carbon::createFromTime(Carbon::now()->hour,Carbon::now()->minute,00,'Example/Zone')->format('H:i:s')
I found the solution. You can use setSeconds(int $value) method:
Carbon::now()->setSeconds(0)->toTimeString()
DB::table('restaurants')
->where('schedule', '=', $schedule)
->where('active', '=', 1)
->whereDate('start_at', '<=', Carbon::today())
->where('daily_at', '=', Carbon::now('Y-m-d H:i')->toTimeString())
use this code
Can you please try with this way:
whereRaw(DATE_FORMAT(daily_at, "%H:%i") = Carbon::now()->format('H:i'))
So final query would be,
DB::table('restaurants')
->where('schedule', '=', $schedule)
->where('active', '=', 1)
->whereDate('start_at', '<=', Carbon::today())
->where('daily_at', '=', Carbon::now()->toTimeString())
->whereRaw(DATE_FORMAT(daily_at, "%H:%i") = Carbon::now()->format('H:i'))

Where clause on join query laravel 4.2

I have 2 tables 'users' and 'instantUsers'. I want to join them on users.id = instantUsers.user_id and want to add 2 where clauses on the resulting. I'm not getting how to do both. The query I'm using is -
DB::table('users')
->join('instantUsers', function($join) use ($userId) {
$join->on('users.id', '=', 'instantUsers.user_id');
})
->where('instantUsers.instantMode', '=', '1')
->where (function($query) use ($userId) {
$query->where('instantUsers.user_id', '!=', $userId);
})
->get();
You can try this one maybe this will help you:
DB::table('users as table1')->join('instantUsers as table2','table1.id','=','table2.fkId') ->where('table2.instantMode','=','1')->where('table2.user_id','!=',$userId)->get();
Your 'instantUsers.instantMode','=','1' expression can be done in a join, resulting in a better performance.
I would write it like this
DB::table('users')
->join('instantUsers', function($join) use ($userId) {
$join
->on('users.id', '=', 'instantUsers.user_id')
->on('instantUsers.instantMode', '=', 1);
})
->where('users.id', '!=', $userId)
->get();

Laravel query builder advanced wheres AND, OR

$query = new TableA;
$query = $query->join('tableB', 'tableA.b_id', '=', 'tableB.id');
$query = $query->where('tableB.something', '=', '1');
$query = $query->where('tableA.something_else', '=', '2');
And it produces:
WHERE something=1 AND something_else=2 AND .. AND....
BUT now - I need this:
WHERE something=1 AND something_else=2 AND (city=city1 OR city=city2 OR city=city3) AND (country=country1 OR country=country2)
Any ideas?
Make use of Advanced Wheres. For your example, it'd be something like this:
->where(function ($query) {
$query->where('city', '=', city1)
->orWhere('city', '=', city2)
->orWhere('city', '=', city3);
})->where(function ($query) {
$query->where('country', '=', country1)
->orWhere('country', '=', country2);
});
Quick method. Read about raw expressions:
http://laravel.com/docs/queries#raw-expressions