oracle取不同日期一列的平均值

oracle take mean value of one column across different dates

有一列名为 Price,另一列名为 Date_1,其中包含从现在到大约一年后的数据。 我想找到 Price 在不同日期的平均值。例如,2 周后、1 个月后、6 个月后...

我可以使用 Case When 功能吗?

鉴于:

Location_id |     Date_1  | Price 
------------+-------------+------
   L_1      | 20-JUL-2016 |  105 
   L_1      | 21-JUL-2016 |  117
   ...      |    ...      |  ... 
   L_1      | 16-MAY-2017 |  103 
   L_2      | 20-JUL-2016 |   99 
   L_2      | 21-JUL-2016 |  106 
   ...      |    ...      |  ... 
   L_2      | 16-MAY-2017 |  120 

获得:

Location_id |  Period  | Average_Price 
------------+----------+--------------
   L_1      | 2  weeks |   ... 
   L_1      | 6 months |   ... 
   L_1      | 1 year   |   ... 
   L_2      | 2 weeks  |   ... 
   L_2      | 6 months |   ...
   L_2      | 1 year   |   ... 

在 "Period" 中,“2 周”表示从开始日期 (sysdate) 开始的 2 周。 "Average_Price" 是那个时期的价格平均值。

谢谢!这个问题解决了。我又发现了一个:

还有一个 table 包含日期信息:

Location_id |  Ex_start_date  | Ex_end_date 
------------+-----------------+--------------
   L_1      | 08-JUN-16       |   30-AUG-16
   L_1      | 21-SEP-16       |   25-SEP-16
   L_1      | 08-MAY-17       |   12-MAY-17
   L_2      | 08-AUG-16       |   21-AUG-16
   L_2      | 24-OCT-16       |   29-OCT-16
   L_2      | 15-MAR-17       |   19-MAR-17

"Ex_Start_date" 和 "Ex_End_date" 之后是 'Non_Ex' 时期。在获得 2 周和 6 个月的平均信息后,我想再添加一列,以获得上述 'Non_Ex' 和 'Ex' 条件的平均价格。

希望能得到如下的table:

Location_id |  Period        | Ex_Condition    |   Average_Price 
------------+----------------+----------------------------------
   L_1      | 2 weeks        |   Ex period     |   ...
   L_1      | 2 weeks        |   Non-Ex period |   ...
   L_1      | 6 months       |   Ex period     |   ...
   L_1      | 6 months       |   Non-Ex period |   ...                                                 
   L_2      | 2 weeks        |   Ex period     |   ...
   L_2      | 2 weeks        |   Non-Ex period |   ...
   L_2      | 6 months       |   Ex period     |   ...
   L_2      | 6 months       |   Non-Ex period |   ...

如果没有日期在 EX Period 或 Non-Ex Period 内,平均价格将 return 'null'。

我怎样才能做到这一点?谢谢!

你可以这样做:

select   location_id,
         period,
         sum(in_period * price) / nullif(sum(in_period), 0) as avg_price
from     (select location_id,
                 price,
                 period,
                 case when mydate - days < sysdate then 1 else 0 end in_period
          from   localprice,
                 ( select '2 weeks' as period, 14 as days from dual
                   union 
                   select '6 months', 183 from dual
                 ) intervals
         ) detail
group by location_id, 
         period

localprice 替换为您的 table 的名称(您没有在问题中提供其名称)。

mydate 替换为日期列的实际名称。我不希望你将它命名为 date,因为这是一个保留字并且需要你始终引用它——不要那样做:选择另一个名称。

dual 是 Oracle 中可用的标准对象,可用于在查询中引入行 - table 某处没有的行。

或者,您可以创建一个 table,其中包含您感兴趣的所有时间段(2 周、4 周...,以及它们代表的天数),并使用它代替并集 select对偶。

这是一个SQL fiddle。请注意,它在 Postgres 上运行,因为此时 Oracle 实例不可用。出于这个原因,我明确创建了 dual 并使用 current_date 而不是 sysdate。但其余的都是一样的。

未测试,因为 OP 未提供可用格式的输入数据。

您可能想要类似

的东西
select   location_id, '2 weeks' as period, avg(price) as average_price
from     base_table
where    price is not null
         and
         "date" between SYSDATE and SYSDATE + 13  
                                -- or however you want to define the two week interval
group by location_id
union all
select   location_id, '6 months' as period, avg(price) as average_price
from     base_table
where    price is not null
         and
         "date" between SYSDATE and add_months(SYSDATE, 6) - 1  
                                -- or however you want to define the six month interval
group by location_id
;

请注意,date 是 Oracle 保留关键字,不应用作列名;如果你这样做,你将不得不使用双引号,完全匹配大小写(大小写),你可能仍然 运行 进入各种问题。最好只使用 table 和非保留字的列名。

这是@trincot 回答的重新措辞版本。它应该在更大的数据集上更快。

  • 不需要的行被跳过,不归零和使用。如果没有符合间隔条件的本地价格,您将不会再获得结果行。
  • 与@mathguy 的回答不同,它仍然只扫描一次 localprice。
  • 如果当地实际价格在日期上有高选择性的指数,那么可以使用。
  • 取消注释 WHERE 子句中的行将有助于尽早丢弃行,即在考虑间隔 table 之前。 ORDERED 提示在现实生活中可能是不必要的,但它演示了将此行与此数据一起使用时的正确解释计划。
  • 在粘合将要唯一的行时,使用 UNION ALL 而不是 UNION

像往常一样,在您根据自己的情况证明答案之前,不要相信任何答案。

WITH localprice AS ( SELECT 'L_1' Location_id, TO_DATE('20-JUN-2016') "DATE", 105 Price FROM DUAL UNION ALL SELECT 'L_1' Location_id, TO_DATE('16-MAY-2017') "DATE", 103 Price FROM DUAL UNION ALL SELECT 'L_2' Location_id, TO_DATE('20-JUN-2016') "DATE", 99 Price FROM DUAL UNION ALL SELECT 'L_2' Location_id, TO_DATE('16-MAY-2017') "DATE", 120 Price FROM DUAL ), intervals AS ( SELECT '2 weeks' AS period, 14 AS days FROM dual UNION ALL SELECT '6 months', 183 FROM dual ) SELECT /*+ ORDERED */ location_id, period, AVG(price) AS avg_price FROM localprice CROSS JOIN intervals WHERE "DATE" >= SYSDATE - days -- AND "DATE" >= SYSDATE - (SELECT MAX(days) FROM intervals) GROUP BY location_id, period