Skip to Main Content
  • Questions
  • How do I get a summary of previous year for a SKU in a view?

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Brett.

Asked: January 08, 2002 - 8:25 am UTC

Last updated: July 22, 2003 - 2:57 pm UTC

Version: 8

Viewed 1000+ times

You Asked

Hi Tom,

I have the following view definition:

create or replace view jl_test_summary_v as
select to_char(b.invoice_date, 'YYYY') year, a.sku sku,
a.part_number part_number, a.model,
sum(decode(to_char(b.invoice_date, 'MM'), '01', quantity, 0)) JAN_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '02', quantity, 0)) FEB_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '03', quantity, 0)) MAR_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '04', quantity, 0)) APR_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '05', quantity, 0)) MAY_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '06', quantity, 0)) JUN_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '07', quantity, 0)) JUL_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '08', quantity, 0)) AUG_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '09', quantity, 0)) SEP_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '10', quantity, 0)) OCT_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '11', quantity, 0)) NOV_QTY,
sum(decode(to_char(b.invoice_date, 'MM'), '12', quantity, 0)) DEC_QTY,
nvl(sum(b.quantity),0) TOT_SALES
from jl_inventory_all_v a, jl_line_items b
where a.sku = b.sku
and b.category = 'Subwoofers'
and b.true_warranty = 'N'
and substr(b.sku,1,1) = '9'
group by to_char(b.invoice_date, 'YYYY'), a.sku, a.part_number, a.model
/

I need to include the total sku quantity for the previous year as well as the previous 2 years (in 2 separate columns) in this view also. How do I go about doing this? The database version is 8.1.7.0.1.

and Tom said...

With 816 EE and up, we have very very cool analytic functions. In your case, the answer is the LAG function:

ops$tkyte@ORA817DEV.US.ORACLE.COM> select year, sku, part_number, model, tot_sales,
2 lag(tot_sales) over ( order by year ) prior_year,
3 lag(tot_sales,2) over ( order by year ) two_years_ago
4 from jl_test_summary_v;

YEAR SKU PART_NUMBER MODEL TOT_SALES PRIOR_YEAR TWO_YEARS_AGO
---- ---------- ----------- ---------- ---------- ---------- -------------
1999 9876 1 1 7800
2000 9876 1 1 15600 7800
2001 9876 1 1 7800 15600 7800


The lag function lets us reach back to prior (or subsequent with LEAD) rows in the result set and incorporate their results in the current row.

If you have my book, I have a whole chapter on these functions. You can also refer to the SQL reference manual (list of functions and syntax) AND the data warehousing guide (exapmles, explanation) for details.


(i created dummy data for this example via)

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into a values ( 9876, 1, 1 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> begin
2 for i in 1 .. 12
3 loop
4 insert into b values ( 9876, add_months(to_date('01-jan-2001'), i-1), 100*i, 'Subwoofers', 'N' );
5 end loop;
6 insert into b
7 select sku, add_months( invoice_date, -12 ), quantity, category, true_warranty from b;
8 insert into b
9 select sku, add_months( invoice_date, -12 ), quantity, category, true_warranty from b;
10 end;
11 /

Rating

  (6 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Very cool function!

Brett Gaston, January 09, 2002 - 10:10 am UTC

I do have your book and will definitely research more about this. Thanks for your help.

use of Lag function

A reader, April 04, 2002 - 4:45 am UTC

The query shown may not work if the data for the year 2000 is missing. For e.g. If we had data for year 1999 and 2001 only. Lag function will show the data og 1999 in year ago column. Which is wrong.

What if I want to see the cumulative sum of previous year and this year together?

Fan Liu, July 11, 2003 - 4:52 pm UTC

Tom, how could I build a query to retrieve the cumulative totals?

YEAR SKU PART_NUMBER MODEL TOT_SALES PRIOR_YEAR THIS_YEAR
---- ---------- ----------- ---------- ---------- ---------- ----------
1999 9876 1 1 7800 7800
2000 9876 1 1 15600 7800 23400
2001 9876 1 1 7800 23400 31200


I came up with a solution like this:

create table sales (
prod_id number,
sale_amount number,
sale_date date)

insert into sales values(1, 100, sysdate - 90);
insert into sales values(2, 200, sysdate - 80);
insert into sales values(3, 300, sysdate - 60);
insert into sales values(1, 200, sysdate - 40);
insert into sales values(2, 400, sysdate - 30);
insert into sales values(4, 500, sysdate - 10);

SELECT sale_month,
LAG(cumulative_total, 1)
OVER (ORDER BY sale_month) total_of_last_month,
LAG(cumulative_total, 0)
OVER (ORDER BY sale_month) total_of_this_month
FROM
( SELECT trunc(sale_date, 'MONTH') sale_month,
SUM(SUM(sale_amount))
OVER (ORDER BY trunc(sale_date, 'MONTH')) cumulative_total
FROM sales
GROUP BY trunc(sale_date, 'MONTH'));

SALE_MONTH TOTAL_OF_LAST_MONTH TOTAL_OF_THIS_MONTH
--------------------- ------------------- -------------------
4/1/2003 300
5/1/2003 300 600
6/1/2003 600 1200
7/1/2003 1200 1700


How could I simplify the query without using two levels of SQL analytical function?

(Continue my previous message)

Fan Liu, July 11, 2003 - 5:11 pm UTC

I tried this in 9.2.0.3:

SELECT
trunc(sale_date, 'MONTH') sale_month,
LAG(SUM(SUM(sale_amount))
OVER (ORDER BY trunc(sale_date, 'MONTH')))
OVER (ORDER BY trunc(sale_date, 'MONTH'))
cumulative_total
FROM sales
GROUP BY trunc(sale_date, 'MONTH'));

It says:
ORA-00935: group function is nested too deeply

Will 10i support this kind of nested analytical functions?

Tom Kyte
July 12, 2003 - 9:02 am UTC


why are you worried about making the query more readable and understandble by nesting it?

This is where inline views excel, you need an inline view (you want to get the LAG of another analytic function -- chicken and egg here -- in order to analyze something, you need to have it)

you will use the nested inline views.

A reader, July 21, 2003 - 4:06 pm UTC

Tom,

I have a similar kind of situation in which I have a table called contacts and these are the columns

comp_id varchar2(10),
comp_name varchar2(20),
fname varchar2(30),
lname varchcar2(30),
telno varchar2(15),
faxno varchar2(15)


we record contacts of our customers, this table has entries which has redundant data

For example lets say someone from "Oracle" calls, his entry is made,next time when this guy calls up and says "Oracle Corp" ( this time Oracle Corp), so a new entry is made,
so same company but 2 entries (at times more than two example GE/General Electric/GE Corp )and yes tel no might be different as that person might be calling from different extension, but the first 6 digits might be the same and last 3 digits might be different.

Now i want to find out the records baased on the criteria that have comp_name similar or same telno or the first six digits of tel. no are similar or fax no. is same or the first 6 digits are similar.

Am thinking of using analytic functions lag and lead,can you provide some help on that.

Thanks

Tom Kyte
July 22, 2003 - 7:56 am UTC

what you are asking to do is actually quite complex -- there are entire products built to do just this.

I don't see how lag/lead or any analytics would work -- as you need an order by to find data "near" other data.

A reader, July 22, 2003 - 10:20 am UTC

Thanks Tom for the feedback, can you mention some products that be of help.



Tom Kyte
July 22, 2003 - 2:57 pm UTC

we have a tool in our warehouse builder (OWB) to do this sort of names cleansing. Most of them are not "real time" solutions (they are very computationally expensive and run in the background).

You might need to build some sort of customized "search" for the person on the end of the phone to use to identify a customer -- or run name matching software at the end of the day.

Anyone else that works in this area out there (I'm not heavy into call center software myself)? they might have some ideas -- check back here later to see if anyone adds something

More to Explore

Analytics

Analytic SQL got you confused? Check out Connor McDonald's complete video course.