繁体   English   中英

DB2查询以查找一年前每个项目的平均销售额

[英]DB2 query to find average sale for each item 1 year previous

在弄清楚如何进行这些查询时遇到了一些麻烦。

通常我有一张桌子

  • sales_ID
  • 员工ID
  • 发售日期
  • 销售价格

我想做的是显示一个视图,显示每个销售项目的员工在sale_date前一年平均销售多少商品。

示例:假设我在销售表中有这个

sales_ID    employee_id    sale_date    sale_price
1           Bob            2016/06/10    100
2           Bob            2016/01/01    75
3           Bob            2014/01/01    475
4           Bob            2015/12/01    100
5           Bob            2016/05/01    200
6           Fred           2016/01/01    30
7           Fred           2015/05/01    50

对于sales_id 1记录,我想将Bob的所有销售额在一年内拉到销售额的月份(因此2015-05-01至2016-05-31,其中3销售额分别为75、100、200),因此最终输出将会

sales_ID    employee_id    sale_date    sale_price    avg_sale
1           Bob            2016/06/10    100          125
2           Bob            2016/01/01    75           275
3           Bob            2014/01/01    475          null
4           Bob            2015/12/01    100          475
5           Bob            2016/05/01    200          87.5
6           Fred           2016/01/01    30           50
7           Fred           2015/05/01    50           null

我尝试做的是这样的

select a.sales_ID, a.sale_price, a.employee_ID, a.sale_date, b.avg_price
from sales a
left join (
     select employee_id, avg(sale_price) as avg_price
     from sales 
     where sale_date between Date(VARCHAR(YEAR(a.sale_date)-1) ||'-'|| VARCHAR(MONTH(a.sale_date)-1) || '-01')
                  and Date(VARCHAR(YEAR(a.sale_date)) ||'-'|| VARCHAR(MONTH(a.sale_date)) || '-01') -1 day
    group by employee_id
) b on a.employee_id = b.employee_id

哪个DB2不喜欢在子查询中使用父表a,但是我想不出如何正确编写此查询。 有什么想法吗?

好。 我想我知道了。 请注意三件事。

  1. 我无法在DB2中对其进行测试,因此我使用了Oracle。 但是语法差不多。
  2. 我没有完全使用您的1年逻辑。 我计算的是current_date减去365天,但是您可以更改内部查询的where子句中的part between ,就像您在问题中提到的那样。
  3. 您提到的预期输出不正确。 因此,对于每个sale_id ,我都采用日期,找到employee_id ,采用该员工最近一年的所有销售额(不包括当前日期),然后取平均值。 如果要更改它,可以更改子查询中的where子句。

     select t1.*,t2.avg_sale from sales t1 left join ( select a.sales_id ,avg(b.sale_price) as avg_sale from sales a inner join sales b on a.employee_id=b.employee_id where b.sale_date between a.sale_date - 365 and a.sale_date -1 group by a.sales_id ) t2 on t1.sales_id=t2.sales_id order by t1.sales_id 

产量

+----------+-------------+-------------+------------+----------+
| SALES_ID | EMPLOYEE_ID |  SALE_DATE  | SALE_PRICE | AVG_SALE |
+----------+-------------+-------------+------------+----------+
|        1 | Bob         | 10-JUN-2016 |        100 | 125      |
|        2 | Bob         | 01-JAN-2016 |         75 | 100      |
|        3 | Bob         | 01-JAN-2014 |        475 |          |
|        4 | Bob         | 01-DEC-2015 |        100 |          |
|        5 | Bob         | 01-MAY-2016 |        200 | 87.5     |
|        6 | Fred        | 01-JAN-2016 |         30 | 50       |
|        7 | Fred        | 01-MAY-2015 |         50 |          |
+----------+-------------+-------------+------------+----------+

您几乎可以通过执行LATERAL来解决原始查询。 外侧允许您引用以前声明的表,如下所示:

select a.sales_ID, a.sale_price, a.employee_ID, a.sale_date, b.avg_price
from sales a
left join LATERAL (
     select employee_id, avg(sale_price) as avg_price
     from sales 
     where sale_date between Date(VARCHAR(YEAR(a.sale_date)-1) ||'-'|| VARCHAR(MONTH(a.sale_date)-1) || '-01')
                  and Date(VARCHAR(YEAR(a.sale_date)) ||'-'|| VARCHAR(MONTH(a.sale_date)) || '-01') -1 day
    group by employee_id
) b on a.employee_id = b.employee_id

但是,我从您的日期算术中收到语法错误,因此使用@Utsav解决方案可产生以下结果:

select a.sales_ID, a.sale_price, a.employee_ID, a.sale_date, b.avg_price
from sales a
left join lateral (
    select employee_id, avg(sale_price) as avg_price
    from sales b
    where a.employee_id = b.employee_id 
     and b.sale_date between  a.sale_date - 365 and a.sale_date -1
    group by employee_id
) b on a.employee_id = b.employee_id

由于我们已经将谓词推入了LATERAL ,因此严格来说没有必要使用on子句:

select a.sales_ID, a.sale_price, a.employee_ID, a.sale_date, b.avg_price
from sales a
left join lateral (
    select employee_id, avg(sale_price) as avg_price
    from sales b
    where a.employee_id = b.employee_id 
     and b.sale_date between  a.sale_date - 365 and a.sale_date -1
    group by employee_id
) b on 1=1

通过使用LATERAL我们删除了对sales表的一个访问。 计划的比较显示:

没有横向加入

访问计划:

        Total Cost:             20,4571
        Query Degree:           1

            Rows 
           RETURN
           (   1)
            Cost 
             I/O 
             |
              7 
           >MSJOIN
           (   2)
           20,4565 
              3 
         /---+----\
        7        0,388889 
     TBSCAN       FILTER
     (   3)       (   6)
     6,81572      13,6402 
        1            2 
       |            |
        7         2,72222 
     SORT         GRPBY 
     (   4)       (   7)
     6,81552      13,6397 
        1            2 
       |            |
        7         2,72222 
     TBSCAN       TBSCAN
     (   5)       (   8)
     6,81488      13,6395 
        1            2 
       |            |
        7         2,72222 
 TABLE: LELLE     SORT  
      SALES       (   9)
       Q6         13,6391 
                     2 
                    |
                  2,72222 
                  HSJOIN
                  (  10)
                  13,6385 
                     2 
              /-----+------\
             7                7 
          TBSCAN           TBSCAN
          (  11)           (  12)
          6,81488          6,81488 
             1                1 
            |                |
             7                7 
      TABLE: LELLE     TABLE: LELLE   
           SALES            SALES
            Q2               Q1

横向加入

访问计划:

    Total Cost:         13,6565
    Query Degree:       1

            Rows
           RETURN
           (   1)
            Cost
             I/O
             |
              7
          >^NLJOIN
          (   2)
           13,6559
              2
         /---+----\
        7          0,35
     TBSCAN       GRPBY
     (   3)       (   4)
     6,81488      6,81662
        1            1
       |            |
        7          0,35
 TABLE: LELLE     TBSCAN
      SALES       (   5)
       Q5         6,81656
                     1
                    |
                     7
              TABLE: LELLE
                   SALES
                    Q1

带框架的窗口功能

DB2尚不支持日期范围内的范围框架,而是使用@mustaccio的巧妙技巧:

https://dba.stackexchange.com/questions/141263/what-is-the-meaning-of-order-by-x-range-between-n-preceding-if-x-is-a-dat

我们实际上只能使用一个表访问并解决问题:

select a.sales_ID, a.sale_price, a.employee_ID, a.sale_date
     , avg(sale_price) over (partition by employee_id 
                             order by julian_day(a.sale_date) 
                             range between 365 preceding
                                       and 1 preceding
                            ) as avg_price 
from sales a 

访问计划:

    Total Cost:             6.8197
    Query Degree:           1

      Rows 
     RETURN
     (   1)
      Cost 
       I/O 
       |
        7 
     TBSCAN
     (   2)
     6.81753 
        1 
       |
        7 
     SORT  
     (   3)
     6.81703 
        1 
       |
        7 
     TBSCAN
     (   4)
     6.81488 
        1 
       |
        7 
 TABLE: LELLE   
      SALES
       Q1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM