0

我一直在考虑这个问题几个小时,但没有运气,所以我认为 SO 上的人可能会提供帮助:)

我有一个表格,其中包含有关商店处理量的数据。下面显示的前三列可以从该表中查询。我要做的是添加第 4 列,该列基本上是关于商店是否已处理 >=150 美元的标志,如果是,将显示相应的日期。这种工作方式是商店超过 150 美元的第一个实例是显示的日期。在第一次达到激活日期之后,后续处理量不计算在内。例如,对于商店 4,只有一个激活日期实例。

store_id  sales_volume   date        activated_date
----------------------------------------------------    
2         5              03/14/2012    
2         125            05/21/2012   
2         30             11/01/2012   11/01/2012    
3         100            02/06/2012
3         140            12/22/2012   12/22/2012
4         300            10/15/2012   10/15/2012
4         450            11/25/2012
5         100            12/03/2012

关于如何构建第四列的任何见解?提前致谢!

4

2 回答 2

1

解决方案首先计算累积销售额。然后,您只需要累积销售额首次超过 150 美元水平时的激活日期。当添加当前销售额使累计金额超过阈值时,就会发生这种情况。以下case表达式处理此问题。

select t.store_id, t.sales_volume, t.date,
       (case when 150 > cumesales - t.sales_volume and 150 <= cumesales
             then date
        end) as ActivationDate
from (select t.*,
             sum(sales_volume) over (partition by store_id order by date) as cumesales
      from t
     ) t

如果您有不支持累积总和的旧版 Postgres,您可以使用如下子查询获取累积销售额:

(select sum(sales_volume) from t t2 where t2.store_id = t.store_id and t2.date <= t.date) as cumesales
于 2013-02-06T22:49:29.620 回答
1

变体 1

您可以LEFT JOIN使用一个表格来计算超过每家商店 150 美元限制的第一个日期:

SELECT t.*, b.activated_date
FROM   tbl t
LEFT   JOIN (
   SELECT store_id, min(thedate) AS activated_date
   FROM  (
      SELECT store_id, thedate
            ,sum(sales_volume) OVER (PARTITION BY store_id
                                     ORDER BY thedate) AS running_sum
      FROM   tbl
      ) a
   WHERE  running_sum >= 150
   GROUP  BY 1
   ) b ON t.store_id = b.store_id AND t.thedate = b.activated_date
ORDER  BY t.store_id, t.thedate;

第一天的计算必须分两步完成,因为累积运行总和的窗口函数必须在单独的SELECT.

变体 2

另一个窗口函数而不是LEFT JOIN. 五月可能不会更快。用 测试EXPLAIN ANALYZE

SELECT *
      ,CASE WHEN running_sum >= 150 AND thedate = first_value(thedate)
               OVER (PARTITION BY store_id, running_sum >= 150 ORDER BY thedate)
       THEN thedate END AS activated_date
FROM  (
   SELECT *
         ,sum(sales_volume)
              OVER (PARTITION BY store_id ORDER BY thedate) AS running_sum
   FROM   tbl
   ) b
ORDER  BY store_id, thedate;

-> sqlfiddle演示两者。

于 2013-02-06T23:05:38.317 回答