2016-01-27 2 views
0

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

Вот пример данных, на которые я смотрю. Кстати, это в Oracle 11g.

Key  Time    Amt 
------ ------------------ ------ 
Null 1-1-2016 00:00 50 
Null 1-1-2016 02:00 50 
Key1 1-1-2016 04:00 30 
Null 1-1-2016 06:00 30 
Null 1-1-2016 08:00 30 
Key2 1-1-2016 10:00 40 
Null 1-1-2016 12:00 40 
Key1 1-1-2016 14:00 30 
Null 1-2-2016 00:00 30 
Key2 1-2-2016 02:00 35 

Конечный результат должен выглядеть следующим образом:

Key Start   Stop    Amt 
------ ---------------- ---------------- ----- 
Null 1-1-2016 00:00 1-1-2016 02:00 100 
Key1 1-1-2016 04:00 1-1-2016 08:00 90 
Key2 1-1-2016 10:00 1-1-2016 12:00 80 
Key1 1-1-2016 14:00 1-2-2016 00:00 60 
key2 1-2-2016 02:00 1-2-2016 02:00 35 

Я был в состоянии получить ключ, чтобы заполнить в Nulls. Ключ не всегда вводится, но считается значением до фактического изменения.

SELECT key ,time ,amt 
FROM (
    SELECT DISTINCT amt, time, 
     ,last_value(amt ignore nulls) OVER (
      ORDER BY time 
      ) key 
    FROM sample 
    ORDER BY time, amt 
    ) 
WHERE amt > 0 
ORDER BY time, key NULLS first; 

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

SELECT key,time, amt 
    , sum(amt) OVER (PARTITION BY key ORDER BY time) AS running_total 
    FROM (SELECT key, time, amt 
      FROM (SELECT DISTINCT 
         amt, 
         time, 
         last_value(amt ignore nulls) OVER (ORDER BY time) key 
        FROM sample 
       ORDER BY time, amt 
       ) 
     WHERE amt > 0 
     ORDER BY time, key NULLS first 
     ) 
ORDER BY time, key NULLS first; 

Любая помощь будет принята с благодарностью. Возможно, использование курсора - единственный способ.

Данные образца образца.

+0

Почему Key 1 есть время остановки в 8:00? – xQbert

ответ

1

Для того, чтобы получить суммы, которые вы ищете вам нужен способ, чтобы сгруппировать значения интересующих вас Вы можете создать группировку ID, используя пару из ROW_NUMBER аналитических функции, разделенные по значению ключа. Однако из-за вашей потребности дублировать KEY значений столбцов этого нужно будет сделать в несколько этапов:

WITH t1 AS (
    SELECT dta.* 
     , last_value(KEY IGNORE NULLS)   -- Fill in the missing 
       OVER (ORDER BY TIME ASC) key2 -- key values 
    FROM your_data dta 
), t2 AS (
    SELECT t1.* 
     , row_number() OVER (ORDER BY TIME)  -- Generate a 
     - row_number() OVER (PARTITION BY key2 -- grouping ID 
           ORDER BY TIME) gp 
    FROM t1 
) 
SELECT t2.* 
    , sum(amt) OVER (PARTITION BY gp, key2 
          ORDER BY TIME) running_sums 
    FROM t2; 

Этот запрос создает бегущую сумму АМТ, которая перезапускает каждый раз, когда основные изменения значения. В то время как следующий запрос, используемый вместо последнего оператора select выше, дает запрошенные результаты, которые я бы не назвал текущей суммой.

SELECT key2 
    , MIN(TIME) start_time 
    , MAX(TIME) stop_time 
    , sum(amt) amt 
    FROM t2 
GROUP BY key2, gp; 

Чтобы увидеть все значения времени вы можете захотеть либо изменить сеанс NLS_DATE_FORMAT, как показано ниже:

ALTER SESSION SET NLS_DATE_FORMAT='DD-MM-RRRR HH24:MI:SS'; 

Или завернуть каждый столбец даты в TO_CHAR функции для вывода целей.

0

Я не уверен, что ваши данные примера имеют отношение к запросам (например, ваши образцы данных - это одна таблица, а в примерах запросов - много запросов). Но, для назначения клавиш, вы можете использовать LAG() с опцией IGNORE NULLS:

select s.*, 
     lag(key ignore nulls) over (order by start) as new_key 
from sample s; 

Затем вы хотите, чтобы сгруппировать группы одного и того же ключа вместе. Один из методов - это разность чисел строк. Последним шагом является агрегация:.

select new_key, min(time), max(time), sum(amount) 
from (select s.*, 
      (row_number() over (order by start) - 
       row_number() over (partition by new_key order by start) 
      ) as grp 
     from (select s.*, 
        lag(key ignore nulls) over (order by start) as new_key 
      from sample s 
      ) s 
    ) s 
group by new_key, grp; 
+0

@Sentinel. , ,Я неправильно понял вопрос. Я пересмотрел ответ, чтобы ответить на вопрос. –

+0

более подробно рассмотрите результаты функции задержки, он не совсем получает то, что хочет OP, поскольку, когда значение ключа изменяется, оно все еще показывает предыдущее значение ключа. Это приводит к тому, что группы отключены на одну строку, если вы не «объедините» значения «ключ» и «новая_key». Оказывается, использование функции 'last_value' действительно является более простым способом. – Sentinel

+0

Спасибо, что сработало! Все еще сохранила функцию last_value. – kwhauser

0

Присвоение номера группы всякий раз, когда Key не NULL может легко быть вычислен вместе с LAG:

LAG(key ignore NULLS) OVER (ORDER BY time) AS new_key, 
COUNT(key) OVER (ORDER BY time ROWS UNBOUNDED PRECEDING) AS grp 
Смежные вопросы