简体   繁体   中英

Oracle: Selecting Sums From Columns as both: YTD (Year to Date), Fiscal YTD

I'm relatively new to Oracle and have been spending the better part of the day trying to write a query to return YTD and Fiscal YTD totals on a column.

A simplified version of the table with only relevant columns looks something like:

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

Where an Order is a recurring charge that reappears in each invoice based on logic elsewhere. What I need to return is the total cost for a given invoice along with the YTD total for the order code as well as the Fiscal YTD (starting Nov 1st) for each order code. For this sample set, my query should return for invoice 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

As of now, all I have is:

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

My attempts at YTD have failed thus far but the dev environment also has very poor data so there's no real way to test it. As of now, I'm planning to create a temp table with fake data to try to figure this out.

EDIT for clarity : The query should return the YTD totals for the given invoice date. For example, were I to query, in 2020, an invoice from May 2018, it should return the YTD totals for each order_code contained within that invoice from Jan 2018 - May 2018

You can use Conditional Aggregation such as

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

Depending on the Edit in the Question, Use a Cross Join Among your table and derived invoice_date from :invoice_num bind variable :

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

Demo

You can use conditional aggregation as following:

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

This solution will use indexes on the invoice_date if there is any.

Cheers!!

Your fiscal year starts in November. This makes the aggregation a big tricky, particularly a version that will work in both October and November.

However, the fiscal year can be calculated by adding two months onto the date and extracting the year. If we take this approach, then one method is:

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;

Here is a db<>fiddle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM