2010-09-03 4 views
1

Предположим, у меня есть эти данные:Возможно ли это SQL-запрос?

Employee Task IsCurrent 
-------- ---- --------- 
Jeff  1  Yes 
Jeff  2  No 
Jane  1  No 
Jane  2  Yes 
Jane  3  No 
Jane  4  No 
Jake  1  Yes 

Сотрудники имеют некоторое количество задач, и одна из них будет ток. Номер задачи указывает порядок - они выполняют задачи по порядку, возвращаясь к началу, когда они сделаны с последним. Мне нужен запрос, чтобы увидеть следующие три задачи. Я бы хотел этот результирующий набор:

Employee CurrentTask NextTask NextTask2 
-------- ----------- -------- --------- 
Jeff  1   2   1 
Jane  2   3   4 
Jake  1   1   1 

Возможно ли это? Я использую SQL 2005

ОБНОВЛЕНИЕ: Извините, я не уточнил, что номера задач не обязательно являются секвенциальными - т.е. у Майка могут быть задачи 10, 23 и 223. Поэтому я не могу просто join, ища следующий порядковый номер задачи.

ответ

5

Использование:

WITH summary AS (
    SELECT t.employee, 
      t.task, 
      t.iscurrent, 
      ROW_NUMBER() OVER (PARTITION BY t.employee 
           ORDER BY t.task) AS rank 
    FROM TABLE t) 
    SELECT a.employee, 
      a.task AS current_task, 
      COALESCE(b.task, y.min_task) AS next_task, 
      COALESCE(c.task, y.min_task) AS next_task2 
    FROM summary a 
    JOIN (SELECT x.employee, 
        MIN(x.task) AS min_task 
      FROM TABLE x 
     GROUP BY x.employee) y ON y.employee = a.employee 
LEFT JOIN summary b ON b.employee = a.employee 
        AND b.rank = a.rank + 1 
LEFT JOIN summary c ON c.employee = a.employee 
        AND c.rank = a.rank + 2     
    WHERE a.iscurrent = 'yes' 

Как я уже говорил ранее, было бы проще, если SQL Server поддерживаются функции LEAD/LAG ...

+0

Хороший! Гораздо более надежным, чем мое решение. –

+0

@a_horse_with_no_name: Thx, но я плохо себя чувствую для кода, играющего в гольф вашего ответа. –

+0

Ну, работает лучше, чем у меня. Хорошая работа;) – cichy

0

Может быть, не самый лучший, но вы можете попробовать этот способ, asuming есть не более 2-х NextTask;)

SELECT e.Employee, e.Task AS CurrentTask, 
(
    SELECT TOP 1 e1.Task FROM dbo.Employees AS e1 WHERE e1.Employee=e.Employee AND e1.Task > e.Task ORDER BY e1.Task ASC 
) AS NextTask, 
(
    SELECT TOP 1 e2.Task FROM dbo.Employees AS e2 WHERE e2.Employee=e.Employee AND e2.Task > (
     SELECT TOP 1 e1.Task FROM dbo.Employees AS e1 WHERE e1.Employee=e.Employee AND e1.Task > e.Task ORDER BY e1.Task ASC 
    ) ORDER BY e2.Task ASC 
) AS NextTask2 
FROM dbo.Employees AS e 
WHERE e.IsCurrent = 'Yes'

PS. возможно, PIVOT сделал бы трюк, но я не добьюсь этого.

0

не должен быть слишком плохим ХП со следующими шагами

Создать временную таблицу с колонками Employee, CurrentTask, NextTask и NextTask2 Вставки записей с каждым сотрудником и их CurrentTask. Это простое заявление SQL ... и вы могли бы объединить шаги 1 и 2.

INSERT INTO #tempTable (Employee, CurrentTask) VALUES Employee, Task WHERE IsCurrent = 'Yes' 

Тогда Вам нужно перебрать эти записи, постепенно обновляя столбцы NextTask и NextTask2, используя комбинацию TOP 1 и Order By Task ASC

1

Если вы заинтересованы только в следующем, и тот, после этого, вы можете использовать следующее:

 
SELECT t.employee, 
     t.task AS current_task, 
     t1.task AS next_task, 
     t2.task AS next_task_2 
FROM tasks t 
    LEFT JOIN tasks t1 ON t1.task = t.task + 1 AND t1.employee = t.employee 
    LEFT JOIN tasks t2 ON t2.task = t1.task + 1 AND t2.employee = t1.employee 
WHERE t.isCurrent = 'yes' 
+0

Это предполагает, что taskIds ВСЕГДА обрабатываются на 1. Я бы ожидал, что это редко будет иметь место ... И я думаю, что у вас есть опечатка, не следует ли читать «t2.task AS next_task_2'? – CaffGeek

+1

@ Chad. Спасибо, что указал на тип. Первоначальный вопрос не указывал, были ли задачи «упорядочения» безразличными или нет. Но это может быть сделано и для этого. –

0

Это проблема двух частей. Во-первых, вам необходимо решить проблему с модулем (перечисление задач в порядке, начиная с текущей задачи):

Шаг 1: постройте запрос, результаты которого выглядят следующим образом (я изменил данные согласно вашему правлению)

Employee IsCurrent OriginalTask [Task+MaxTask] as Task 
-------- ----  ------------ ---------------------- 
Jeff  Yes  37   15 
Jeff  No  44   22 
Jane  No  55   13 
Jane  Yes  67   25 
Jane  No  73   31 
Jane  No  84   42 
Jake  Yes  38   19 

Шаг 2: сделать UNION с первоначальным запросом

Employee IsCurrent Task OriginalTask 
-------- ----  ---- ------------ 
Jeff  Yes  15 15 
Jeff  No  22 22 
Jeff  Yes  37 15 
Jeff  No  44 22 
Jane  No  13 13 
Jane  Yes  25 25 
Jane  No  31 31 
Jane  No  42 42 
Jane  No  55 13 
Jane  Yes  67 25 
Jane  No  73 31 
Jane  No  84 42 
Jake  Yes  19 19 
Jake  Yes  38 19 

Шаг 3: Подавить строки, где задача # < низкий ток или задача #> = высокий ток

Employee IsCurrent Task OriginalTask 
-------- ----  ---- ------------ 
Jeff  Yes  15 15 
Jeff  No  22 22 
Jane  Yes  25 25 
Jane  No  31 31 
Jane  No  42 42 
Jane  No  55 13 
Jake  Yes  19 19 

Теперь у вас есть данные о модуле и обычная сводная проблема.