【问题标题】:Grouping data by overlapping date selections in Oracle SQL通过 Oracle SQL 中的重叠日期选择对数据进行分组
【发布时间】:2019-12-01 16:59:48
【问题描述】:

我想知道是否有一种有效的方法来对特定重叠时间范围的数据进行分组。我掌握这个练习的主要目标是查询这张表:

transaction_date  | item_type | profit
  'dd/mm/yy'            ""        ''

示例:

transaction_date  | item_type | profit
  03/01/2018           Book        2
  03/05/2018           Book        5
  04/05/2018           Book        6
  03/06/2018           Misc.       20

并获得

(1) 按周和年分组,因此查询具有 year | 列日期

这已经成功完成,只需使用 group by 和以下几行

to_char(transaction_date, 'YY'), to_char(transaction_date, 'WW')

其中,与 item_type 和利润的其他一些期望的分组一起,给出了

year | week  | item_type | profit
 18     17        Book        2
 18     18        Book       11
 18     22        Misc       20

(2) 一个附加列,包含过去 4 周的利润(如果条目是在第 7 周,这将是第 3-6 周的总计,而不是正好 4 周前。)

year | week  | item_type | profit  | profit_last4wks
 18     17        Book        2           0
 18     18        Book       11           2
 18     22        Misc       20           0

这一步就是问题,因为我目前对如何处理它以及从哪里开始作为第一步感到非常困惑。任何建议或正确方向的观点都会非常有帮助。

我的想法是在单独的查询中执行步骤 (1)(2) 然后加入,但甚至获得 (2) 分别让我难住了。我还认为可以先获取 (1),然后以某种方式附加所需的列。

【问题讨论】:

  • 样本数据和期望的结果真的会有所帮助。
  • 看来您不仅仅按周分组(按年份和周数标识),还按 item_type 分组。 (如果您将任何给定周的所有项目类型组合在一起,那么您将不会在输出中包含 item_type)。请澄清。
  • 还有什么在一年的第一周展示?应该是去年最后4周价格的总和吗?
  • @mathguy,是的,抱歉,它也被分组为 item_type、利润(理想情况下是 profit_last4wks),我会澄清一下。
  • @Tejash,没错。虽然现在想起来,WK53只有一两天,所以理想情况下应该加入WK52

标签: sql oracle group-by overlap


【解决方案1】:

正如 mathguy 所说,您按 2 to_char 函数和 item_type 进行分组。获取profit_last4weeks数据,需要用到解析版的SUM函数,看the doc for the analytical clauseSUM

【讨论】:

  • 查找了分析函数,不知道它们,感谢您的有用评论
【解决方案2】:

为了将前几周相加,您必须能够计算出哪一周在给定周之前。根据您的定义(即合并第 52 周和第 53 周),2018/52 周是 2019/01 的前一周。此计算最好使用运行周数来完成。从 0 年第 1 周开始,例如 2019 年的第一周是第 104989 周,2018 年的最后一周是第 104988 周。

您想显示一周的利润以及前四个星期的利润总和。使用SUM OVER 会很容易,但可能存在间隙(缺少几周),因此我们不知道必须取回多少行。示例:

年份 |周 |利润 |最后4周 -----+------+--------+--------- 2018 | 52 | 10 | 0 2019 | 01 | 20 | 10(2018/49 至 2018/52 => 1 行) 2019 | 02 | 30 | 30(2018/50 至 2019/01 => 2 行) 2019 | 06 | 40 | 30(2019/02 至 2019/05 => 1 行)

我正在使用LAG 解决此问题,以查看第 -1、-2、-3 和 -4 行是否在前四个星期的所需范围内。然后我再次使用LAG 来获得这周的利润。也许现在还没有想到一种更优雅的方式。

with weekdata as
(
  select
    extract(year from transaction_date) * 52 +
    to_number(to_char(transaction_date, 'ww')) as runweek,
    profit
  from mytable
)
select
  trunc(runweek / 52) as year,
  mod(runweek, 52) as week,
  sum(profit),
  case when lag(runweek, 1) over (order by runweek) between runweek - 4 and runweek - 1 then
    lag(sum(profit), 1) else 0 end +
  case when lag(runweek, 2) over (order by runweek) between runweek - 4 and runweek - 1 then
    lag(sum(profit), 2) else 0 end +
  case when lag(runweek, 3) over (order by runweek) between runweek - 4 and runweek - 1 then
    lag(sum(profit), 3) else 0 end +
  case when lag(runweek, 4) over (order by runweek) between runweek - 4 and runweek - 1 then
    lag(sum(profit), 4) else 0 end as profit_last4wks
from weekdata
group by runweek
order by runweek;

查询没有考虑类型,因为我不清楚您希望如何处理它。也许您想要每周显示一个结果行,只需添加受影响类型的列表 (LISTAGG DISTINCT)。或者您希望每周有一个结果行和类型,您必须将类型添加到 GROUP BY 子句并添加 PARTITION 子句。

【讨论】:

  • 查找了分区子句的分析函数,不知道它们。我最终按周对它们进行分组,然后将其用作分区子句的子查询。
猜你喜欢
  • 2017-08-17
  • 2016-11-17
  • 2015-05-30
  • 1970-01-01
  • 2016-12-08
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多