【问题标题】:DB2 query to find average sale for each item 1 year previousDB2 查询查找每件商品 1 年前的平均销售额
【发布时间】:2016-06-11 03:36:55
【问题描述】:

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

一般来说我有一张桌子

  • sales_ID
  • Employee_ID
  • 销售日期
  • 销售价格

我想要做的是有一个视图,显示每个销售项目的员工在销售日期前 1 年的平均销售额。

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

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 有 75、100、200 的 3 个销售)所以最终输出将是

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) 给定查询中的问题是什么。你有什么错误吗?内部查询是否可以自行正常运行? (2) 能否给出一些样本数据和预期输出?
  • 不识别 a.sale_date 错误 SQLCODE = -204 和 SQLSTATE=42704 将使用示例编辑问题
  • 这仍然令人困惑。 Bob3 销售有不同的 sales_id?这些应该是什么输出?请举例说明至少有 2 名员工的销售额不同,以及您在所有行上的预期输出。
  • 不,我不知道如何编写 where 子句,它只查找行中销售项目仅 1 年前的项目。
  • 对于sales_id=2,平均销售额如何275。你能解释一下它的数学原理吗?

标签: sql db2


【解决方案1】:

好的。我想我想通了。请注意 3 件事。

  1. 我无法在 DB2 中测试它,所以我使用了 Oracle。但语法或多或少是一样的。
  2. 我没有完全使用您的 1 年逻辑。我计算 current_date 减去 365 天,但您可以更改内部查询中 where 子句中的 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 |          |
+----------+-------------+-------------+------------+----------+

【讨论】:

    【解决方案2】:

    您几乎可以通过 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 连接,我们删除了一项对销售表的访问。方案对比显示:

    无横向连接

    访问计划:

            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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多