2010-11-23 11 views
2

J'ai une table qui a une table comme celle-ci.alternative à lag commande SQL

Month-----Book_Type-----sold_in_Dollars 
Jan----------A------------ 100 
Jan----------B------------ 120 
Feb----------A------------ 50 
Mar----------A------------ 60 
Mar----------B------------ 30 

et ainsi de suite

Je dois calculer les ventes prévues pour chaque mois et le type livre basé sur les 2 derniers mois de ventes. Donc pour Mars et le type A ce serait (100 + 50)/2 = 75 Pour Mars et le type B c'est 120/1 car il n'y a pas de données pour Fév.

J'essayais d'utiliser la fonction de décalage, mais cela ne fonctionnerait pas car il manque des données sur quelques lignes.

Des idées à ce sujet?

Répondre

0

Pour autant que je sache, vous pouvez donner une valeur par défaut de retard(): (. En supposant la colonne Mois ne contient pas vraiment JAN ou février mais réel, dates ordonnables)

SELECT Book_Type, 
     (lag(sold_in_Dollars, 1, 0) OVER(PARTITION BY Book_Type ORDER BY Month) + lag(sold_in_Dollars, 2, 0) OVER(PARTITION BY Book_Type ORDER BY Month))/2 AS expected_sales 
    FROM your_table 
GROUP BY Book_Type 

0

Qu'en est-il quelque chose comme (pardonnez la syntaxe du serveur SQL, mais vous voyez l'idée):

Select Book_type, AVG(sold_in_dollars) 
from MyTable 
where Month in (Month(DATEADD('mm'-1,GETDATE)),Month(DATEADD('mm'-2,GETDATE))) 
group by booktype 
+0

Il veut 120/1, pas (120 + 0)/2, ce qui est stupide. – milan

+0

branchez les valeurs dans et exécutez-le. – SteveCav

+0

Pour autant que je sache, la moyenne ignore les valeurs nulles, donc si vous faites la moyenne sur deux lignes et que l'une des valeurs est nulle, alors elle ne divise que 1. –

1

comme il prévoit de ne pas tenir compte des valeurs manquantes, cela devrait probablement. Ne pas avoir une base de données pour le tester sur le moment, mais lui donnera une autre aller le matin

select 
    month, 
    book_type, 
    sold_in_dollars, 
    avg(sold_in_dollars) over (partition by book_type order by month 
    range between interval '2' month preceding and interval '1' month preceding) as avg_sales 
from myTable; 

Cela suppose sorte de ce mois a une date et type de données peut être triée sur ... si elle est juste une chaîne de texte alors vous aurez besoin d'autre chose.

Normalement, vous pouvez simplement utiliser rows between 2 preceding and 1 preceding mais cela prendra les deux points de données précédents et pas nécessairement les deux mois précédents s'il manque des lignes.

Vous pourriez vous débrouiller avec le lag mais ce serait un peu plus compliqué.

+0

+1 - Je pense qu'il devrait être partitionné par mois plutôt que book_type. Juste une opinion ... – Art

0

Une jointure externe de partition peut aider à créer les données manquantes. Créez un ensemble de mois et joignez ces valeurs à chaque ligne par mois et effectuez la jointure une fois pour chaque type de livre. J'ai créé les mois de Janvier à Avril dans cet exemple:

with test_data as 
(
    select to_date('01-JAN-2010', 'DD-MON-YYYY') month, 'A' book_type, 100 sold_in_dollars from dual union all 
    select to_date('01-JAN-2010', 'DD-MON-YYYY') month, 'B' book_type, 120 sold_in_dollars from dual union all 
    select to_date('01-FEB-2010', 'DD-MON-YYYY') month, 'A' book_type, 50 sold_in_dollars from dual union all 
    select to_date('01-MAR-2010', 'DD-MON-YYYY') month, 'A' book_type, 60 sold_in_dollars from dual union all 
    select to_date('01-MAR-2010', 'DD-MON-YYYY') month, 'B' book_type, 30 sold_in_dollars from dual 
) 
select book_type, month, sold_in_dollars 
    ,case when denominator = 0 then 'N/A' else to_char(numerator/denominator) end expected_sales 
from 
(
    select test_data.book_type, all_months.month, sold_in_dollars 
    ,count(sold_in_dollars) over 
     (partition by book_type order by all_months.month rows between 2 preceding and 1 preceding) denominator 
    ,sum(sold_in_dollars) over 
     (partition by book_type order by all_months.month rows between 2 preceding and 1 preceding) numerator 
    from 
    (
     select add_months(to_date('01-JAN-2010', 'DD-MON-YYYY'), level-1) month from dual connect by level <= 4 
    ) all_months 
    left outer join test_data partition by (test_data.book_type) on all_months.month = test_data.month 
) 
order by book_type, month