tags:

views:

50

answers:

1

I have two tables with the following schema:

CREATE TABLE sales_data (
     sales_time date NOT NULL,
     product_id integer NOT NULL,
     sales_amt double NOT NULL
);

CREATE TABLE date_dimension (
  id integer  NOT NULL,
  datestamp   date NOT NULL,
  day_part    integer NOT NULL,
  week_part   integer NOT NULL,
  month_part  integer NOT NULL,
  qtr_part    integer NOT NULL, 
  year_part   integer NOT NULL, 
);

I want to write two types of queries that will allow me to calculate:

  • period on period change (e.g. week on week change)
  • change in period on period change (e.g. change in week on week change)

I would prefer to write this in ANSI SQL, since I dont want to be tied to any particular db.

[Edit]

In light of some of the comments, if I have to be tied to a single database (in terms of SQL dialect), it will have to be PostgreSQL

The queries I want to write are of the form (pseudo SQL of course):

Query Type 1 (Period on Period Change)
=======================================
a). select product_id, ((sd2.sales_amt - sd1.sales_amt)/sd1.sales_amt) as week_on_week_change from sales_data sd1, sales_data sd2, date_dimension dd where {SOME CRITERIA)

b). select product_id, ((sd2.sales_amt - sd1.sales_amt)/sd1.sales_amt) as month_on_month_change from sales_data sd1, sales_data sd2, date_dimension dd where {SOME CRITERIA)


Query Type 2  (Change in Period on Period Change)
=================================================
a). select product_id, ((a2.week_on_week_change - a1.week_on_week_change)/a1.week_on_week_change) as change_on_week_on_week_change from 
(select product_id, ((sd2.sales_amt - sd1.sales_amt)/sd1.sales_amt) as week_on_week_change from sales_data sd1, sales_data sd2, date_dimension dd where {SOME CRITERIA)
as a1), 
(select product_id, ((sd2.sales_amt - sd1.sales_amt)/sd1.sales_amt) as week_on_week_change from sales_data sd1, sales_data sd2, date_dimension dd where {SOME CRITERIA) as a2)
WHERE {SOME OTHER CRITERIA}
+2  A: 

PostgreSQL 8.4 has window functions which can help to calculate period-on-period change without needing to join a table against itself.

For example, to get a week-on-week comparison:

create view week_on_week_sales as
select week_part,
       week_sales,
       lag(week_sales, 1) over(order by week_part) as previous_week_sales
from (select week_part,
             sum(sales_amt) as week_sales
      from sales_data
           join date_dimension 
                on sales_data.sales_time = date_dimension.datestamp
      group by date_dimension.week_part) x
order by week_part

Similarly to get the second derivative, you can wrap that in a further subquery:

select week_part,
       week_sales - previous_week_sales as change,
       week_sales - previous_week_sales
              - lag(week_sales - previous_week_sales, 1) over(order by week_part)
              as change_in_change
from week_on_week_sales

The window syntax is standardised in SQL:2003, I believe. However, implementations are not all the same. For example, SQL Server notably doesn't implement LEAD() and LAG() functions. I tested this on Postgresql 8.4. Oracle supports similar functions (and Postgresql usually follows Oracle), and I believe DB2 also supports these queries although the exact syntax may differ. Others?

araqnid
@araqnid: +1 For the code snippet. It is so concise. (Whoo - making my head spin though!). Now to make sure I understand it and to test it on some data then I will accept it as my final answer. Thanks for your help
morpheous
@araqnid: if this works, I'd like to give you some bonus points. The code is so elegant, I can't just "take it and run", I know I have less points than you, but I would still like to give you some of my points - seriously, I have been wrestling with this for a LONG time... (is there a way I can give you some of my points to show my gratitude?)
morpheous
@morpheous you almost definitely want to read http://www.postgresql.org/docs/current/static/tutorial-window.html if you haven't already. And depesz's blog post http://www.depesz.com/index.php/2009/01/21/waiting-for-84-window-functions/ is good too. Glad you like it- it seems like all the SQL questions I've answered recently have involved window functions!
araqnid