限制SQL中的子查询

时间:2017-01-31 06:39:48

标签: sql postgresql

我的情况有点难以描述。我将尝试用一个例子和我想要的结果来解释。

我有三张桌子

 Employee

 | id | Name  |
 |----+-------|
 |  1 | Alice |
 |  2 | Bob   |
 |  3 | Jane  |
 |  4 | Jack  |


 Task

 | id | employee_id | description         |
 |----+-------------+---------------------|
 |  1 |           1 | Fix bug             |
 |  2 |           1 | Implement feature   |
 |  3 |           1 | Deploy master       |
 |  4 |           2 | Integrate feature   |
 |  5 |           2 | Fix cosmetic issues |


 Status

 | id | task_id |  time | details   | Terminal |
 |----+---------+-------+-----------+----------|
 |  1 |       1 | 12:00 | Assigned  | false    |
 |  2 |       1 | 12:30 | Started   | false    |
 |  3 |       1 | 13:00 | Completed | true     |
 |  4 |       2 | 12:10 | Assigned  | false    |
 |  5 |       2 | 14:00 | Started   | false    |
 |  6 |       3 | 12:15 | Assigned  | false    |
 |  7 |       4 | 12:20 | Assigned  | false    |
 |  8 |       5 | 12:25 | Assigned  | false    |
 |  9 |       4 | 12:30 | Started   | false    |

(我还将这些内容放在http://sqlfiddle.com/#!9/728c85/1

的sqlfiddle页面中

基本思想是我有一些员工和任务。这些任务可以分配给员工,当他们处理这些任务时,他们会不断添加" status"行。

每个状态条目都有一个字段" terminal"这可能是真的也可能是假的。

如果某个任务的最后一个状态条目的终端设置为true,那么该任务结束,并且无需再进行任何操作。

如果分配给员工的所有任务都已结束,则该员工将被视为免费

我需要获得一份免费员工名单。在给定员工的情况下,这基本上意味着他们所有具有状态的任务列表。所以,像Alice这样的事情

 | Task              | Completed |
 |-------------------+-----------|
 | Fix bug           | true      |
 | Implement feature | false     |
 | Deploy master     | false     |

我从中知道她现在不是免费的,因为有错误的'完成的条目。

我该怎么做?如果我的表格不适合这种查询,我也非常喜欢这方面的建议。

(因为我想按每个用户订购每个任务的状态,然后将它们限制在最后一行,我将这个问题命名为这样的问题。)

更新

有人告诉我,status字段应该真正进入任务表,而Status表应该简单地是一个日志表。

4 个答案:

答案 0 :(得分:3)

我会想把这个状态放在任务表中。 (请参阅我对此请求的评论。)但是,这里有两个选择免费员工的问题:

如果无法重新打开任务,则很简单:通过检查是否存在terminal = true的记录来获取所有未完成的任务。免费员工都没有完成任务。

select *
from employee
where id not in
(
  select employee_id
  from task
  where id not in (select task_id from status where terminal = true)
);

但是,如果可以重新打开任务,那么您可以执行相同操作,但必须找到最后一个状态。这可以通过Postgre的DISTINCT ON来完成。

select *
from employee
where id not in
(
  select employee_id
  from task
  where not 
  (
    select distinct on (task_id) terminal 
    from status 
    where task_id = task.id
    order by task_id, id desc
  )
);

(我使用ID来查找每个任务的最后一个条目,因为没有日期的时间似乎不合适。如果任务总是只在一天内运行,则只能使用时间列。)

SQL fiddles:

答案 1 :(得分:0)

您必须将所有状态分组为gheter,然后您可以使用MAX()查找其中一个是否为真,如下所示:

SELECT t.description,  MAX(s.terminal)
FROM Employee e
INNER JOIN task t ON t.employee_id = e.id
INNER JOIN status s ON s.task_id = t.id
GROUP BY t.id;

如果您希望仅为一位用户添加此类内容WHERE e.id = 1

答案 2 :(得分:0)

我希望这能帮到你...... ??

    select E.Name,T.id as[Task Id],T.description,S.Terminal from Employee E 
inner join Task T on E.id=T.employee_id 
inner join Status S on S.task_id=T.id 
where  e.id not in (select employee_id from Task where id in (select task_id from Status where Terminal='true' and details='Completed') )

答案 3 :(得分:0)

希望这有帮助

select T.employee_id, T.description, S.Terminal
from Employee E
INNER JOIN Task T ON E.id=T.employee_id
INNER JOIN (Select task_id, max(id) as status_id FROM Status GROUP BY task_id) as ST on T.id=ST.task_id 
INNER JOIN Status S on S.id=ST.status_id