sql中的SQL连接和子查询

Posted

技术标签:

【中文标题】sql中的SQL连接和子查询【英文标题】:SQL join and sub query in sql 【发布时间】:2012-08-15 16:22:31 【问题描述】:

我有一个表 employee 包含列 id(主键)*employee_name* 和另一个名为 employee_works 的表,其中包含列 *employee_id*(引用employee.id 的外键)* start_date* (datetime), *finish_date* (datetime)。

以下是员工表的一些数据:

 **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 表:

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 值表示员工仍在工作。 我需要一个查询来显示员工中的人员列表,如果他们与我们一起工作,谁仍在我们公司工作,谁离开了,如果可能的话,他们与我们一起工作了多长时间。 示例:

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

我的尝试:

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

我还想在另一列中获取员工工作的总天数?

【问题讨论】:

【参考方案1】:

问题是您有一个分组依据,但没有用于状态定义的聚合。 mysql 不会给你一个语法错误。相反,它会给你一个随机状态:

试试这样的:

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

mysql的这个“特性”被称为隐藏列。编写 mysql 的人(以及许多使用它的人)认为这是一个很棒的功能。许多使用其他数据库的人只是摸不着头脑,想知道为什么任何数据库都会表现得如此奇怪。

顺便说一句,您应该检查是否为多次受雇的人分配了新 ID。如果是这样,您的查询可能需要更高级的名称匹配方法。

【讨论】:

错误:每个派生表都必须有自己的别名 上述查询中的每个派生表都有自己的别名。你在最后一行写上“pg”了吗? 谢谢它的工作,我怎样才能得到员工在另一列工作的总天数【参考方案2】:

尽量简化你的条件。

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

【讨论】:

以上是关于sql中的SQL连接和子查询的主要内容,如果未能解决你的问题,请参考以下文章

sql查询语句学习,多表查询和子查询以及连接查询

sql99和sql92分别实现连接和子查询和分页查询

oracle之连接查询和子查询

SQL主外键和子查询

sql不存在和子查询

SQL 示例查询解决方案(按技术分组和子查询技术)