2010-05-26 6 views
1

J'ai deux tables avec le schéma suivant:changement de calcul (sur une période) pour un champ daté

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, 
); 

Je veux écrire deux types de requêtes qui me permettent de calculer:

  • période de changement de période (par exemple la semaine sur le changement de semaine)
  • changement de période de changement de période (par exemple, changement de la semaine sur le changement de semaine)

Je préférerais écrire ceci en ANSI SQL, puisque je ne veux pas être lié à un db particulier.

[Modifier]

À la lumière de certains commentaires, si je dois être lié à une base de données unique (en termes de dialecte SQL), il devra être PostgreSQL

Le requêtes Je veux écrire sont de la forme (pseudo SQL bien sûr):

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} 
+1

La plupart des bases de données implémentent différemment la gestion des dates, chacune utilisant des fonctions différentes pour manipuler les dates. Par conséquent, il est difficile d'écrire une approche «toutes bases de données» pour votre question. De plus, je ne suis pas tout à fait sûr de ce que vous recherchez, j'ai inclus des exemples de données et les résultats attendus de la requête que vous voulez. –

+0

TBH, votre schéma n'est déjà pas applicable à tous les produits de base de données. Par exemple, SQL Server 2005 entre autres n'implémente pas un type de données 'date' et SQL Server en général n'implémente pas un type de données nommé' double' bien qu'il implémente un équivalent appelé 'float'. – Thomas

+0

@Thomas, SQL Server 2008 a un type de données 'date' ainsi qu'un type de données' time', voir: http://msdn.microsoft.com/en-us/library/ms187752.aspx, mais encore une fois, cette montre simplement à quel point chaque base de données et même la version d'une base de données peuvent être différentes. –

Répondre

2

PostgreSQL 8.4 dispose de fonctions de fenêtre qui peuvent aider à calculer période en période de changement sans avoir besoin de se joindre à une table contre elle-même.

Par exemple, pour obtenir une comparaison semaine en semaine:

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 

De même pour obtenir la dérivée seconde, vous pouvez conclure que dans un sous-requête plus:

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 

La syntaxe de la fenêtre est normalisé en SQL:2003, je crois. Cependant, les implémentations ne sont pas toutes identiques. Par exemple, SQL Server n'implémente pas les fonctions LEAD() et LAG(). J'ai testé cela sur Postgresql 8.4. Oracle supporte des fonctions similaires (et Postgresql suit généralement Oracle), et je crois que DB2 supporte également ces requêtes bien que la syntaxe exacte puisse différer. Autres?

+0

+1 Pour l'extrait de code. C'est tellement concis. (Whoo - faire tourner ma tête si!). Maintenant, pour m'assurer que je le comprends et pour le tester sur certaines données, je l'accepterai comme ma réponse finale. Merci pour votre aide – morpheous

+0

si cela fonctionne, je voudrais vous donner quelques points bonus.Le code est si élégant, je ne peux pas juste "prendre et courir", je sais que j'ai moins de points que vous, mais je voudrais toujours vous donner quelques-uns de mes points - sérieusement, je me suis battu avec cela pour un LONGTEMPS ... (y a-t-il un moyen de vous donner quelques uns de mes points pour montrer ma gratitude?) – morpheous

+0

@morpheous vous avez presque certainement envie de lire http://www.postgresql.org/docs/current/static/tutorial -window.html si vous ne l'avez pas déjà fait. Et l'article du blog de depesz http://www.depesz.com/index.php/2009/01/21/waiting-for-84-window-functions/ est également bon. Heureux que vous l'aimiez, il semble que toutes les questions SQL auxquelles j'ai répondu récemment ont impliqué des fonctions de fenêtre! – araqnid

Questions connexes