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
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.