Mysql Foreach from one table to another

Viewed 266

I have 2 tables, First table is user and second table is user_attendance.

In the user attendance I'm inserting IN and OUT per line, so 1 line for IN and 1 line for OUT.

I want a MySQL select(so I don't have to do it on Php) which will loop for every ID in users and get the last OUT and first IN of that user in user table.

I tried doing it on Php by selecting first all the ID in user and looping it Via php and Select the 1st in and Last out of that Id in attendance. Like so.

$userCreds = DB::table('users')->select('user_id', 'username')->get();

$emailBody = '<table border="1"><thead><tr><th>Employee ID</th><th>Employee Name</th><th>Date</th><th>IN</th><th>OUT</th></tr></thead><tbody>';

        foreach ($userCreds as $userCred) {
           $userAttendance = DB::select( 
                            DB::raw(
                                "SELECT username,
                                    (
                                        SELECT TIME_FORMAT(time(b.server_time), '%r')
                                        FROM `users` a
                                        LEFT JOIN user_attendance b
                                        ON a.user_id = b.user_id
                                        WHERE a.user_id = $userCred->user_id
                                        AND (b.server_time between '$ysDate' and '$yeDate')
                                        AND b.action = 'IN' ORDER BY b.server_time ASC LIMIT 1
                                    ) as TimeIn,
                                    (
                                        SELECT TIME_FORMAT(time(b.server_time), '%r')
                                        FROM `users` a
                                        LEFT JOIN user_attendance b
                                        ON a.user_id = b.user_id
                                        WHERE a.user_id = $userCred->user_id
                                        AND (b.server_time between '$ysDate' and '$yeDate')
                                        AND b.action = 'OUT' ORDER BY b.server_time DESC LIMIT 1
                                    ) as TimeOut
                                FROM users
                                WHERE user_id = $userCred->user_id"
                            )
                        ); 

            $emailBody .= '<tr><td>'.$userCred->user_id.'</td><td>'.$userCred->username.'</td><td>'.date('Y-m-d',(strtotime ( '-1 day' , strtotime ( $date) ) )).'</td><td>'.$userAttendance[0]->TimeIn.'</td><td>'.$userAttendance[0]->TimeOut.'</td></tr>';
        }

Instead of doing it on Php, I want it to be done on the Mysql side so I can actually create a view which will be stored ever now and done for recording purposes.

What I need is like this

user table

user_id | username

01 | piglet

02 | pooh

03 | tiger

user_attendance table

user_id | servertime | action

01 | 2019-10-10 08:00:00 | IN

01 | 2019-10-10 09:00:00 | OUT

01 | 2019-10-10 10:00:00 | IN

01 | 2019-10-10 18:00:00 | OUT

02 | 2019-10-10 07:45:00 | IN

02 | 2019-10-10 09:00:00 | OUT

02 | 2019-10-10 10:00:00 | IN

02 | 2019-10-10 19:50:00 | OUT

Result will be

user_id | date | IN | OUT

01 | 2019-20-10 | 08:00:00 | 18:00:00

02 | 2019-20-10 | 07:45:00 | 19:50:00

1 Answers

Here's the refactored sql query.

first is to get your users table second is the join the IN time third is to join the OUT time fourth is get the max() and min() time of user id then group by a.user_id.

SELECT a.user_id, TIME_FORMAT(time(min(b.server_time)), '%r') as TimeIn, TIME_FORMAT(time(max(c.server_time)), '%r') as TimeOut
FROM `users` a
LEFT JOIN user_attendance b ON a.user_id = b.user_id and (b.server_time between '$ysDate' and '$yeDate') and b.action = 'IN'
LEFT JOIN user_attendance c ON a.user_id = c.user_id and (c.server_time between '$ysDate' and '$yeDate') and c.action = 'OUT'
GROUP BY a.user_id
Related