SQL 查询帮助 - 任务排序、分组和状态+日期条件问题

Posted

技术标签:

【中文标题】SQL 查询帮助 - 任务排序、分组和状态+日期条件问题【英文标题】:SQL Query Help - task ordering, grouping and status + date conditions problem 【发布时间】:2008-10-29 23:12:26 【问题描述】:

希望我能公正地解决问题,因为在标题中总结它太难了! (欢迎在 cmets 中提出建议)

好的,这是我的桌子:

Tasks
  task_id        (number)
  job_id         (number)
  to_do_by_date  (date)
  task_name      (varchar / text)
  status         (number)
  completed_date (date)

为了参数,让我们设置 status 的值:

1 = New
2 = InProgress
3 = Done

而我在尝试做的事情是创建一个可以撤回所有任务的查询:

job_id 的任何任务都有status 完成 除非job_id 的所有任务都已完成,但一项或多项任务今天的completed_date 除外 按to_be_done_by 日期排序,但将所有job_id 任务组合在一起 所以job_id 和下一个 `to_do_by_date' 任务首先显示

关于数据的一些信息:

job_id 可以有任意数量的任务

这是我试图获得的输出示例:

task_id   job_id   to_do_by_date   task_name   status   completed_date
   1        1        yesterday        -          3        yesterday
   2        1        today            -          3        today
   3        2        now              -          3        today
   4        2        2 hours time     -          2        null
   5        2        4 hours time     -          2        null
   6        2        tomorrow         -          1        null
   7        3        3 hours time     -          2        null
   8        3        tomorrow         -          1        null
   9        3        tomorrow         -          1        null

我正在使用 Oracle 10g,因此 Oracle 或 ANSI SQL 的答案,或有关如何解决此问题的提示将是理想的,如果您的解决方案需要,我可以创建视图或将其包装在存储过程中以从应用程序中卸载逻辑它。

这是一个 sql 脚本,它将创建上面显示的示例测试数据:

create table tasks (task_id number, job_id number, to_do_by_date date, task_name varchar2(50), status number, completed_date date);
insert into tasks values (0,0,sysdate -2,    'Job 0, Task 1 - dont return!', 3, sysdate -2);
insert into tasks values (1,1,sysdate -1,    'Job 1, Task 1', 3, sysdate -1);
insert into tasks values (2,1,sysdate -2/24, 'Job 1, Task 2', 3, sysdate -2/24);
insert into tasks values (3,2,sysdate,       'Job 2, Task 1', 3, sysdate);
insert into tasks values (4,2,sysdate +2/24, 'Job 2, Task 2', 2, null);
insert into tasks values (5,2,sysdate +4/24, 'Job 2, Task 3', 2, null);
insert into tasks values (6,2,sysdate +1,    'Job 2, Task 4', 1, null);
insert into tasks values (7,3,sysdate +3/24, 'Job 3, Task 1', 2, null);
insert into tasks values (8,3,sysdate +1,    'Job 3, Task 2', 1, null);
insert into tasks values (9,3,sysdate +1,    'Job 3, Task 3', 1, null);
commit;

非常非常感谢您的帮助:o)

【问题讨论】:

【参考方案1】:

显然,您将不得不稍微解决这个问题,但我希望您明白这一点。

SELECT 
    task_id, job_id, to_do_by_date, task_name, status, completed_date
FROM
    Tasks
WHERE
    job_id IN (
        SELECT job_id 
        FROM Tasks 
        WHERE status <> 'Done' 
        GROUP BY job_id)
    OR
    job_id IN (
        SELECT job_id 
        FROM Tasks 
        WHERE status = 'Done' AND completed_date = 'Today'
            AND job_id NOT IN (SELECT job_id FROM Tasks WHERE status <> 'Done' GROUP BY job_id)
        GROUP BY job_id)
ORDER BY
    job_id, to_do_by_date

【讨论】:

【参考方案2】:

我同意贾斯汀的观点——我不明白为什么会返回 2。

这是一个使用解析函数根据逻辑描述返回正确行的查询。

select * from
(
select t.*,
       min(status) over (partition by job_id) min_status_over_job,
       max(status) over (partition by job_id) max_status_over_job,
       sum(case when trunc(completed_date) = trunc(sysdate)-1 then 1 else 0 end) 
                   over (partition by job_id) num_complete_yest
from   tasks t
)
where  max_status_over_job < 3
       or (min_status_over_job = 3 and num_complete_yest > 0)
/

【讨论】:

对不起,那是我的错,我没有正确地表达我的意图。我已经更新了问题的那一部分:o/【参考方案3】:

鉴于您的要求,我不清楚为什么应在结果中返回 job_id 2。有一个任务的状态为完成,因此它不符合第一个条件

job_id 的所有任务都有一个 状态完成

并且有些任务的状态不是完成,所以它不符合第二个条件

除了一个job_id的所有任务 已完成,但有一项或多项任务 完成日期为今天

还有其他原因应该包含 job_id = 2 吗?

SQL> ed
Wrote file afiedt.buf

  1  select task_id, job_id, to_do_by_date, task_name, status, completed_date
  2    from tasks t1
  3   where not exists( select 1
  4                       from tasks t2
  5                      where t1.job_id = t2.job_id
  6                        and t2.status  = 3)
  7      or ((not exists( select 1
  8                        from tasks t3
  9                       where t1.job_id  = t3.job_id
 10                         and t3.status != 3))
 11          and
 12          exists (select 1
 13                    from tasks t4
 14                   where t1.job_id = t4.job_id
 15                     and trunc(t4.completed_date) = trunc(sysdate)))
 16*   order by job_id, to_do_by_date
SQL> /

   TASK_ID     JOB_ID TO_DO_BY_ TASK_NAME           STATUS COMPLETED
---------- ---------- --------- --------------- ---------- ---------
         1          1 28-OCT-08 Job 1, Task 1            3 28-OCT-08
         2          1 29-OCT-08 Job 1, Task 2            3 29-OCT-08
         7          3 29-OCT-08 Job 3, Task 1            2
         8          3 30-OCT-08 Job 3, Task 2            1
         9          3 30-OCT-08 Job 3, Task 3            1

【讨论】:

很好,很抱歉造成的混乱,但这应该是“job_id 的任何任务都没有完成” - 即,如果 job_id 有任何未完成的任务,那么所有应显示 job_id 的任务 我已根据您的回答更新了问题。感谢您的回答,请接受我的歉意,因为我没有明确表达我的意图:o/【参考方案4】:

我不使用 Oracle,也没有手边的 Sql Server - 但这应该会让您非常接近。

SELECT Tasks.*
FROM Tasks
JOIN (
   --Undone
   SELECT Job_Id
   FROM Tasks
   WHERE
     Status <> 3
   UNION
   --Done today
   SELECT Job_Id
   FROM Tasks
   WHERE
     Status = 3
     AND Completed_Date = TODAY()
) as UndoneOrDoneToday ON
   Tasks.Job_Id = UndoneOrDoneToday.Job_Id
JOIN (
   SELECT Job_Id, MIN(to_do_by_date) as NextToDoByDate
   FROM Tasks
   GROUP BY Job_id
) as NextJob ON
   Tasks.Job_Id = NextJob.Job_id
ORDER BY
   NextJob.NextToDoByDate, 
   Tasks.Job_Id, --If NextToDoByDate isn't unique, this should order jobs together
   Tasks.to_do_by_date, --This may not be needed, but would put eg., task 7 due today higher than task 6 due tomorrow
   Tasks.Task_Id --this should be last

编辑:大多数其他答案似乎都按 job_id、to_do_by 排序。这看起来适用于示例数据,但不符合以下要求:

按 to_be_done_by 日期排序,但将所有 job_id 任务组合在一起 所以首先显示下一个 to_do_by_date 任务的 job_id

【讨论】:

以上是关于SQL 查询帮助 - 任务排序、分组和状态+日期条件问题的主要内容,如果未能解决你的问题,请参考以下文章

mysql查询分组中最大的值

sqlserver 分组查询

SQL - 如何在一年中的每个日期按年龄和状态对项目进行分组/计数 - 第 2 部分

mysql分组排序,取每组第一条数据

sql多表分组查询并排序的问题

mysql分组排序后取出几条记录,