Oracle SQL - 在AVG函数中过滤组

时间:2014-06-17 21:28:51

标签: sql database oracle group-by

我查询'销售'表格为'价格',按产品名称分组:

SELECT product_name, sale_price, sale_date,
SUM(CASE WHEN sales.sale_date = TO_DATE ('14-JUN-14', 'DD-MON-YY') - 1 THEN (sale_price) ELSE 0 END) sale_yday,
SUM(CASE WHEN sales.sale_date = TO_DATE ('14-JUN-14', 'DD-MON-YY') - 7 THEN (sale_price) ELSE 0 END) sale_lweek,
AVG(sales.sale_price) ten_wk_avg,
STDDEV(sales.sale_price) ten_wk_stddev
FROM sales
WHERE sales.sale_date IN
    (TO_DATE ('14-JUN-14', 'DD-MON-YY'),
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 1,
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 7,
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 2 * 7,
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 3 * 7,
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 4 * 7,
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 5 * 7,
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 6 * 7,
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 7 * 7,
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 8 * 7,
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 9 * 7,
    TO_DATE ('14-JUN-14', 'DD-MON-YY') - 10 * 7)
GROUP BY sales.product_name

AVG功能并没有按照我需要做的事情 - 我需要它平均只采用前10周,而不是之前的10周PLUS今天和昨天如上所述。与标准偏差相同的情况。有没有更好的方法来构建此查询,以便我可以按照描述获得ten_wk_avg和ten_wk_stddev?

2 个答案:

答案 0 :(得分:1)

使用条件聚合:

SELECT product_name, sale_price, sale_date,
       SUM(CASE WHEN sales.sale_date = TO_DATE('14-JUN-14', 'DD-MON-YY') - 1 THEN (sale_price) ELSE 0 
           END) as sale_yday,
       SUM(CASE WHEN sales.sale_date = TO_DATE('14-JUN-14', 'DD-MON-YY') - 7 THEN (sale_price) ELSE 0 
           END) as sale_lweek,
       AVG(CASE WHEN sales.sale_date < TO_DATE('14-JUN-14', 'DD-MON-YY') - 1 THEN sales.sale_price
           END) as ten_wk_avg,
       STDDEV(CASE WHEN sales.sale_date < TO_DATE('14-JUN-14', 'DD-MON-YY') - 1 THEN sales.sale_price
              END) as ten_wk_stddev

. . .

avg()stddev()忽略NULL值,这就是else中没有case子句的原因。

答案 1 :(得分:0)

首先,您应该考虑在查询中要求的内容。您想要过去10周内每次促销的product_name,sale_price和sale_date。这可能是数十,数百或数千的销售。那么你想要(每个产品)昨天的销售额,上周的销售额以及过去10周的销售额的平均值和标准差。这些是每种产品的单一价值,但它们将会一遍又一遍地重复几十次,数百次或数千次。这真的是你想要的吗?

这是一个查询,它将为您提供所需的汇总值 - 每个产品一行。如果您想看到它的实际效果,请尝试SQL Fiddle检查。它可能不是最紧凑的查询,但是它被分解为很容易遵循的块状态。

WITH
By_Week AS(
  SELECT  product_name, sale_date, sale_price,
          trunc(sale_date, 'd') as week_of,
          (trunc(SYSDATE, 'd') - trunc(sale_date, 'd')) / 7 AS weeks_ago
  FROM    sales
),
Weekly_Sales AS(
  SELECT  product_name, 
          sum( CASE WHEN weeks_ago BETWEEN 1 AND 10 THEN sale_price END ) AS ten_wk_avg,
          stddev( case when weeks_ago between 1 and 10 then sale_price end ) AS ten_wk_stddev
  FROM    By_Week
  group by product_name
)
SELECT  w.product_name,
        sum( CASE WHEN trunc(SYSDATE) - w.sale_date = 1 THEN w.sale_price END ) AS sale_yday,
        sum( CASE WHEN weeks_ago = 1 THEN sale_price END ) AS sale_lweek,
        s.ten_wk_avg, s.ten_wk_stddev
FROM    By_Week w
JOIN    Weekly_Sales s
  ON    s.product_name = w.product_name
GROUP BY w.product_name, s.ten_wk_avg, s.ten_wk_stddev
order by w.product_name;

顺便说一句,你已经标记了Oracle和MySQL。上面的查询适用于Oracle。 MySQL没有CTE(iirc),但你可以把它们作为内联视图。