подсчет последних последовательных строк с одинаковыми данными с использованием табибитозана - PullRequest
0 голосов
/ 24 мая 2018

Мой проект использует базу данных Oracle SQL.У меня есть хронологическая таблица, которая добавляет статус задачи на еженедельной основе, и я пытаюсь запросить количество недель, в течение которых задача, которая в данный момент отклоняется от нормы, была отклонена.Вот пример выдержки из моей исходной исторической таблицы:

ID  WEEK    ON_TRACK
1   1   N
1   2   Y
1   3   N
1   4   N
1   5   N
2   1   N
2   2   N
2   3   Y
2   4   Y
2   5   N
3   1   N
3   2   N
3   3   Y
3   4   Y
3   5   Y

Я хочу вернуть количество последовательных "N" значений в ON_TRACK, начиная с последнего добавления.Для приведенных выше примеров данных я бы хотел, чтобы запрос возвращал:

ID  WKS_OFF_TRACK
1   3
2   1
3   0

Я провел некоторое исследование, и похоже, что метод Табибитозан является наиболее логичным, и я нашел достаточнопримеры для получения максимальных последовательных значений, которые соответствуют 1 критерию, но у меня возникают проблемы с настройкой, чтобы вернуть самые последние последовательные значения, которые соответствуют 2 критериям (ID и ON_TRACK).*

--this step creates a temp table with unique IDs for each weekly append to the historical table, and a 1 (if ON_TRACK = N) or 0 (if ON_TRACK = Y). This results in the expected info.
WITH HIST_TBL AS (
    SELECT DISTINCT(ID),
    CASE ON_TRACK
        WHEN 'N' THEN 1
        ELSE 0
        END AS OFF_TRACK,
    WEEK 
    FROM SOURCE_HISTORICAL_TBL
    ORDER BY ID,WEEK DESC)
-- end of temp table 

--this is where Im struggling I want one line per project number, and the sum of the latest string of 1s (weeks the task has been off track), until a 0 is reached.
SELECT ID,
       SUM(OFF_TRACK) AS WKS_OFF_TRACK
FROM   (SELECT WEEK,
               ID,
               OFF_TRACK,
               ROW_NUMBER() OVER (ORDER BY WEEK DESC) - ROW_NUMBER() OVER 
(PARTITION BY ID,OFF_TRACK ORDER BY WEEK DESC) GRP
        FROM   HIST_TBL)
GROUP BY ID, GRP
ORDER BY ID;

Этот код приводит к совокупной сумме всех недель, в течение которых не выполнялся каждый проект, для данных моего примера:

ID  WKS_OFF_TRACK
1   4
2   3
3   2

Любые идеи, где я ошибаюсь

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Вы можете сделать это за одно сканирование таблицы:

Скрипка SQL

Настройка схемы Oracle 11g R2 :

CREATE TABLE SOURCE_HISTORICAL_TBL ( ID, WEEK, ON_TRACK ) AS
SELECT 1, 1, 'N' FROM DUAL UNION ALL
SELECT 1, 2, 'Y' FROM DUAL UNION ALL
SELECT 1, 3, 'N' FROM DUAL UNION ALL
SELECT 1, 4, 'N' FROM DUAL UNION ALL
SELECT 1, 5, 'N' FROM DUAL UNION ALL
SELECT 2, 1, 'N' FROM DUAL UNION ALL
SELECT 2, 2, 'N' FROM DUAL UNION ALL
SELECT 2, 3, 'Y' FROM DUAL UNION ALL
SELECT 2, 4, 'Y' FROM DUAL UNION ALL
SELECT 2, 5, 'N' FROM DUAL UNION ALL
SELECT 3, 1, 'N' FROM DUAL UNION ALL
SELECT 3, 2, 'N' FROM DUAL UNION ALL
SELECT 3, 3, 'Y' FROM DUAL UNION ALL
SELECT 3, 4, 'Y' FROM DUAL UNION ALL
SELECT 3, 5, 'Y' FROM DUAL UNION ALL
SELECT 4, 1, 'N' FROM DUAL UNION ALL
SELECT 5, 1, 'Y' FROM DUAL;

Запрос 1 :

SELECT ID,
       GREATEST(
         COALESCE( MAX( CASE ON_TRACK WHEN 'N' THEN WEEK END ), 0 )
         - COALESCE( MAX( CASE ON_TRACK WHEN 'Y' THEN WEEK END ), 0 ),
         0
       ) AS weeks
FROM   SOURCE_HISTORICAL_TBL
GROUP BY id
ORDER BY id

Результаты :

| ID | WEEKS |
|----|-------|
|  1 |     3 |
|  2 |     1 |
|  3 |     0 |
|  4 |     1 |
|  5 |     0 |
0 голосов
/ 24 мая 2018

Вот один метод, который предполагает, что люди были «на ходу» в определенный момент времени:

select sht.id, count(*)
from SOURCE_HISTORICAL_TBL sht
where sht.week > (select max(sht2.week)
                  from SOURCE_HISTORICAL_TBL sht2
                  where sht2.id = sht.id and sht2.on_track = 'Y'
                )
group by sht.id;

В противном случае вам нужно еще одно условие:

select sht.id, count(*)
from SOURCE_HISTORICAL_TBL sht
where sht.week > (select max(sht2.week)
                  from SOURCE_HISTORICAL_TBL sht2
                  where sht2.id = sht.id and sht2.on_track = 'Y'
                 ) or
      not exists (select 1
                  from SOURCE_HISTORICAL_TBL sht2
                  where sht2.id = sht.id and sht2.on_track = 'Y'
                 )
group by sht.id;

Вы также можетесформулируйте их как аналитические функции:

select id,
       sum(case when week > max_week_y or max_week_y is null then 1 else 0 end) as max_off_track
from (select sht.*,
             max(case when on_track = 'Y' then week end) over (partition by id) as max_week_y
      from SOURCE_HISTORICAL_TBL sht
     ) sht
group by id;

Обратите внимание, что эта версия вернет 0 s для людей, которые в настоящее время находятся на пути.

...