Oracle: выбор сумм из столбцов как обоих: YTD (с начала года), Fiscal YTD

Я относительно новичок в Oracle и провел большую часть дня, пытаясь написать запрос, чтобы вернуть итоги YTD и Fiscal YTD в столбце.

Упрощенная версия таблицы только с соответствующими столбцами выглядит примерно так:

INVOICE_NUM  |  INVOICE_DATE  |  ORDER_CODE  |  ORDER_COST
    509         '14-FEB-20'      'ORD001'         34.99
    509         '14-FEB-20'      'ORD002'         14.99
    509         '14-FEB-20'      'ORD003'         59.99
    428         '16-JAN-20'      'ORD001'         34.99
    428         '16-JAN-20'      'ORD002'         14.99
    306         '14-DEC-19'      'ORD001'         34.99
    306         '14-DEC-19'      'ORD002'         14.99
    201         '15-NOV-19'      'ORD001'         34.99
    108         '16-OCT-19'      'ORD001'         34.99

Где Заказ представляет собой периодический платеж, который снова появляется в каждом счете на основе логики в другом месте. Что мне нужно вернуть, так это общую стоимость данного счета, а также общую сумму с начала года для кода заказа, а также финансовый год с начала года (начиная с 1 ноября) для каждого кода заказа. Для этого набора образцов мой запрос должен вернуть счет 509:

ORDER_CODE  |  CURRENT_INVOICE_TOTAL  |  YTD_TOTAL  |  FISCAL_YTD_TOTAL
 'ORD001'             34.99                69.69           139.96
 'ORD002'             14.99                29.98            44.97
 'ORD003'             59.99                59.99            59.99

На данный момент все, что у меня есть, это:

SELECT 
    order_code
    SUM(order_cost)
FROM 
    table_name
WHERE 
    invoice_num = :invoice_num
GROUP BY
    order_code

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

ИЗМЕНИТЬ для ясности: запрос должен возвращать итоги с начала года для указанной даты выставления счета. Например, если бы я запросил в 2020 году счет за май 2018 года, он должен вернуть итоги с начала года для каждого кода заказа, содержащегося в этом счете с января 2018 года по май 2018 года.


person Michael Cole    schedule 16.01.2020    source источник


Ответы (3)


Ваш финансовый год начинается в ноябре. Это делает агрегирование очень сложным, особенно версия, которая будет работать как в октябре , так и в ноябре.

Однако финансовый год можно рассчитать, добавив два месяца к дате и извлекая год. Если мы выберем этот подход, то один из методов:

select order_code,
       max(order_cost) keep (dense_rank first order by invoice_date desc) as current_invoice_total,
       sum(case when trunc(invoice_date, 'YEAR') = trunc(sysdate, 'YEAR')
                then order_cost
           end) as YTD,
       sum(case when trunc(invoice_date + interval '2' month, 'YEAR') = trunc(sysdate + interval '2' month, 'YEAR') 
                then order_cost
           end) as Fiscal_YTD
from t
where trunc(invoice_date, 'YEAR') = trunc(sysdate, 'YEAR') or 
      trunc(invoice_date + interval '2' month, 'YEAR') = trunc(sysdate + interval '2' month, 'YEAR')
group by order_code;

Вот скрипт db‹>.

person Gordon Linoff    schedule 17.01.2020
comment
На самом деле это довольно близко к тому, что у меня было (относительно YTD, поскольку я еще не отважился на фискальный YTD). Это могло быть что-то, что я не смог уточнить, но я не гарантирую выполнение запроса в течение того же периода времени, что и invoice_date. Похоже, что использование sysdate вернет неправильную сумму с начала года, если я выберу invoice_num, который произошел, скажем, в 2018 году. Мысли? Спасибо! - person Michael Cole; 17.01.2020
comment
@МайклКоул. . . Я немного смущен. Если вы хотите, чтобы это была другая дата, просто используйте эту дату вместо sysdate. Данные вашего примера предполагают, что вам нужен самый последний год/финансовый год. У вас есть строка с датой октября 2019 г., и она не включена в результаты. - person Gordon Linoff; 18.01.2020

Вы можете использовать conditional aggregation следующим образом:

Select order_code, 
       order_cost as CURRENT_INVOICE_TOTAL,
       Sum(case when invoice_date >= trunc(sysdate,'YEAR') then order_cost end) as YTD_TOTAL,
       Sum(case when invoice_date < add_months(trunc(sysdate,'YEAR'), 10) order_cost) as FISCAL_YTD_TOTAL
  From table_name
 Where invoice_num = :invoice_num
   And invoice_date >= add_months(trunc(sysdate,'YEAR'), -2)
   And invoice_date < add_months(trunc(sysdate,'YEAR'), 12)
Group by order_code, order_cost

Это решение будет использовать индексы на invoice_date, если они есть.

Ваше здоровье!!

person Popeye    schedule 17.01.2020
comment
На самом деле это довольно близко к тому, что у меня было (относительно YTD, поскольку я еще не отважился на фискальный YTD). Это могло быть что-то, что я не смог уточнить, но я не гарантирую выполнение запроса в течение того же периода времени, что и invoice_date. Похоже, что использование sysdate вернет неправильную сумму с начала года, если я выберу invoice_num, который произошел, скажем, в 2018 году. Мысли? Спасибо! - person Michael Cole; 17.01.2020

Вы можете использовать Conditional Aggregation, например

SELECT order_code, 
       SUM(CASE WHEN invoice_num = :invoice_num then order_cost END ) AS current_invoice_total,
       SUM(CASE WHEN to_char(sysdate,'yyyy') = to_char(invoice_date,'yyyy') then
                  order_cost
              END ) AS ytd_total,
       SUM(CASE WHEN invoice_date 
             BETWEEN to_date(to_char(sysdate,'yyyy')-1||'-11-01','yyyy-mm-dd')
                 AND to_date(to_char(sysdate,'yyyy')||'-10-31'  ,'yyyy-mm-dd')
             THEN
                  order_cost
              END ) AS fiscal_ytd_total              
  FROM t
 GROUP BY order_code
 ORDER BY order_code

В зависимости от Изменить в вопросе используйте Cross Join среди вашей таблицы и полученную invoice_date из :invoice_num переменной привязки:

SELECT t.order_code, 
       SUM(CASE WHEN invoice_num = :invoice_num THEN order_cost END ) 
             AS current_invoice_total,
       SUM(CASE WHEN invoice_date 
             BETWEEN TRUNC(invoice_date2,'yyyy')
                 AND invoice_date2
                THEN
                     order_cost
                END ) AS ytd_total,
       SUM(CASE WHEN invoice_date 
             BETWEEN to_date(to_char(invoice_date2,'yyyy')-1||'-11-01','yyyy-mm-dd')
                 AND invoice_date2
                THEN
                     order_cost
                END ) AS fiscal_ytd_total           
  FROM t
 CROSS JOIN ( SELECT MAX(invoice_date) AS invoice_date2 
                FROM t 
               WHERE invoice_num = :invoice_num ) t2
 GROUP BY order_code
 ORDER BY order_code

Демо

person Barbaros Özhan    schedule 17.01.2020
comment
На самом деле это довольно близко к тому, что у меня было (относительно YTD, поскольку я еще не отважился на фискальный YTD). Это могло быть что-то, что я не смог уточнить, но я не гарантирую выполнение запроса в течение того же периода времени, что и invoice_date. Похоже, что использование sysdate вернет неправильную сумму с начала года, если я выберу invoice_num, который произошел, скажем, в 2018 году. Мысли? Спасибо! - person Michael Cole; 17.01.2020
comment
просто замените sysdate (текущая дата) на литерал значения даты из 2018 года, скажем, дату «2018-04-05», тогда вы получите суммарную стоимость для даты диапазона «2017-11-01» и даты «2018-10-31». ' как финансовый_год, а для даты диапазона "2018-01-01" и даты "2018-10-31" как ytd_total, например, вы можете динамически выбирать из текущего и / или предыдущего года @MichaelCole - person Barbaros Özhan; 17.01.2020
comment
Этот оператор выбора будет выполняться как запрос гибернации, которому задан только номер invoice_num, поэтому есть ли способ сначала получить invoice_date этого конкретного счета, а затем использовать эту конкретную дату, а не sysdate или дату, введенную вручную? - person Michael Cole; 17.01.2020
comment
В качестве альтернативы я мог бы получить отдельный запрос для получения invoice_date, а затем передать эту дату в предоставленный вами запрос. Просто хотел посмотреть, есть ли способ убрать здесь посредника. - person Michael Cole; 17.01.2020