Справка по SQL-запросам - проблема с упорядочением, группировкой и состоянием + состояние даты - PullRequest
2 голосов
/ 30 октября 2008

Надеюсь, я справлюсь с задачей, потому что было слишком сложно обобщить ее в названии! (предложения приветствуются в комментариях)

Правильно, вот мой стол:

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

для аргументов давайте сделаем значения статуса:

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 'отображается первым

некоторая информация о данных:

  • a 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;


Большое, большое спасибо за вашу помощь: о)

Ответы [ 4 ]

2 голосов
/ 30 октября 2008

Я согласен с Джастином - я не понимаю, почему возвращается 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)
/
2 голосов
/ 30 октября 2008

Очевидно, вам придется немного исправить это, но я надеюсь, что вы поняли идею.

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
0 голосов
/ 30 октября 2008

Я не пользуюсь 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

Edit: большинство других ответов сортируются по job_id, to_do_by. Это выглядит для данных примера, но не соответствует требованиям:

упорядочено по дате to_be_done_by, но сгруппированы все задачи job_id вместе таким образом, job_id со следующей задачей to_do_by_date показывается первым

0 голосов
/ 30 октября 2008

Учитывая ваши требования, для меня не очевидно, почему 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...