简体   繁体   中英

SQL join and sub query in sql

I have a table employee having columns id (primary key), *employee_name* and another table called employee_works with columns *employee_id* (foreign key referencing employee.id), *start_date* (datetime), *finish_date* (datetime).

Here are some datas for employee table:

 **id**   **employee_name**
 1      employee A
 2      employee B
 3      employee C
 4      employee D
 5      employee E
 6      employee F
 7      employee G

employee_works table:

1  2010-01-01 00:00:00   NULL
2  2010-01-01 00:00:00   2010-01-10 10:00:00"
2  2010-01-13 00:00:00   2010-01-15 10:00:00"
2  2010-01-31 00:00:00   NULL
4  2010-02-18 00:00:00   2011-01-31 00:00:00"
6  2010-02-18 00:00:00   NULL

NULL value means the employee still works. I need to get a single query showing the list of persons in employee, if they worked with us, who still works in our company, who left and if possible, for how long they worked with us. Example:

id     employee_name       status
1      Employee A       Still with us
3      Employee C       Never worked
4      Employee D       Left

My attempt:

SELECT emp.id,emp.name,
CASE
WHEN occ.finish_date is NULL and occ.start_date is NOT NULL THEN 'Still working'
WHEN occ.finish_date is NULL and occ.start_date is NULL THEN 'Never Worked'
WHEN occ.finish_date is NOT  NULL and occ.start_date is NOT NULL THEN 'Left'
END
AS status

FROM employee AS emp
LEFT JOIN employee_works AS occ ON emp.id=occ.employee_id 
GROUP BY emp.id, occ.finish_date

I also want to get the total no of days the employees have worked in another column?

The problem is that you have a group by but no aggregations for the definition of status. Mysql does not give you a syntax error. Instead, it gives you a random status:

Try something like this instead:

select id, name,
       (CASE WHEN statusint = 3
             THEN 'Still working'
             WHEN statusint = 1 or statusint is null
             THEN 'Never Worked'
             WHEN statusint = 2
             THEN 'Left'
        END) AS status,
       days_worked
from (SELECT emp.id, emp.name,
             max(CASE WHEN occ.departure_date is NULL and occ.start_date is NOT NULL
                      THEN 3
                      WHEN occ.departure_date is NULL and occ.start_date is NULL
                      THEN 1
                      WHEN occ.departure_date is NOT NULL and occ.start_date is NOT NULL
                      THEN 2
                 END) AS statusint,
             sum(datediff(coalesce(departure_date, curdate()), occ.start_date
                ) as days_worked
      FROM employee emp LEFT JOIN
           employee_works occ
           ON emp.id=occ.employee_id
      GROUP BY emp.id, emp.name
     ) eg

This "feature" of mysql is called hidden columns. Folks who write mysql (and many who use it) think this is a great feature. Many people who use other databases just scratch their heads and wonder why any database would act so strangely.

By the way, you should check if someone who is employeed multiple times gets assigned a new id. If so, your query might need more advanced name matching methods.

Try to simplify your condition.

SELECT  a.*, 
        CASE
            WHEN b.employeeID IS NULL THEN 'NEVER WORKED'
            WHEN b.finish_date IS NULL THEN 'STILL WORKING'
            WHEN DATE(b.finish_date) < CURDATE() THEN 'LEFT'
        END as `Status`
FROM    employee a
            LEFT JOIN employee_works b
                on a.id = b.employeeID

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM