【问题标题】:Counting current items by month按月计算当前项目
【发布时间】:2020-06-23 05:33:50
【问题描述】:

我正在尝试从数据库日志表中创建按服务区域分组的活动设备的月度统计。我想我已经完成了 90%。我有一个月份列表,以及存在的项目总数,并按地区分组。

但是,我还需要知道每个项目在每个月的第一天的状态,这是我坚持的部分。例如,项目 1 在 1 月份位于区域 A,但在 2 月份移动到区域 B。项目 2 在 2 月被标记为“非活动”,因此不应计算在内。我现有的查询将始终将区域 A 中的项目 1 和项目 2 计为“活动”。

我可以正确地表明第 3 项在 3 月被删除,第 4 项直到 4 月计数才出现。我意识到我得到了第一个值,因为我的查询指定了最小日期,我只是不确定如何更改它以获得我想要的。

我想我正在寻找一种按 Max(OperationDate) 为每个月分组的方法。

表格如下所示:

| EQUIPID | EQUIPNAME | EQUIPACTIVE | DISTRICT | REGION |        OPERATIONDATE | OPERATION |
|---------|-----------|-------------|----------|--------|----------------------|-----------|
|       1 |    Item 1 |           1 |        1 |      A | 2015-01-01T00:00:00Z |       INS |
|       2 |    Item 2 |           1 |        1 |      A | 2015-01-01T00:00:00Z |       INS |
|       3 |    Item 3 |           1 |        1 |      A | 2015-01-01T00:00:00Z |       INS |
|       2 |    Item 2 |           0 |        1 |      A | 2015-02-10T00:00:00Z |       UPD |
|       1 |    Item 1 |           1 |        1 |      B | 2015-02-15T00:00:00Z |       UPD |
|       3 |    (null) |      (null) |   (null) | (null) | 2015-02-21T00:00:00Z |       DEL |
|       1 |    Item 1 |           1 |        1 |      A | 2015-03-01T00:00:00Z |       UPD |
|       4 |    Item 4 |           1 |        1 |      B | 2015-03-10T00:00:00Z |       INS |

还有一个包含我关心的属性的子表。它的结构类似。不幸的是,由于之前的设计决策,这两个表之间的操作没有关联。任何连接都需要使用 EquipmentID 完成,并为每个日期匹配重叠状态。

当前查询:

--cte to build date list
 WITH calendar (dt) AS
 (SELECT &fromdate from dual
      UNION ALL
    SELECT Add_Months(dt,1)
    FROM calendar
    WHERE dt < &todate)
 
SELECT dt, a.district, a.region, count(*)
FROM
  (SELECT EQUIPID, DISTRICT, REGION, OPERATION, MIN(OPERATIONDATE ) AS FirstOp, deleted.deldate
    FROM Equipment_Log
    LEFT JOIN
      (SELECT EQUIPID,MAX(OPERATIONDATE) as DelDate
        FROM Equipment_Log
        WHERE OPERATION = 'DEL'
        GROUP BY EQUIPID
      ) Deleted
    ON  Equipment_Log.EQUIPID = Deleted.EQUIPID
    WHERE OPERATION <> 'DEL' --AND additional unimportant filters
    GROUP BY EQUIPID,DISTRICT, REGION , OPERATION, deldate
  ) a
  INNER JOIN calendar
  ON  (calendar.dt >= FirstOp AND calendar.dt < deldate) 
    OR (calendar.dt >= FirstOp AND deldate is null)
  LEFT JOIN 
      ( SELECT EQUIPID, MAX(OPERATIONDATE) as latestop
      FROM SpecialEquip_Table_Log
      --where SpecialEquip filters
      group by EQUIPID
      ) SpecialEquip
    ON a.EQUIPID = SpecialEquip.EQUIPID and calendar.dt >= SpecialEquip.latestop
    
GROUP BY dt, district, region
ORDER BY dt, district, region

【问题讨论】:

  • 如果一月份出现的项目,三月份被删除了,但是二月份的项目没有条目应该出现在二月份吗?
  • 是的,没错。期待查看您提供的答案。

标签: sql oracle


【解决方案1】:

只对每个 id 进行最后一次操作。这就是 row_number() 和 where rn = 1 所做的。

我们有日历和数据。制作partitioned join

我假设您需要填写缺少 id 条目的月份的值。所以需要nvl(lag() ignore nulls),因为如果某物出现在 1 月,它仍然存在于 2 月、3 月,我们需要从最后一个非空行开始的区、区域值。

现在您拥有一切都值得考虑的事情了。您提到SpecialEquip_Table_Log 的那部分取决于您,因为您左加入了该表并且以后没有使用它,那么它是做什么用的?有需要就加入,有id。

db<>fiddle

with 
  calendar(mth) as (
    select date '2015-01-01' from dual union all
    select add_months(mth, 1) from calendar where mth < date '2015-05-01'),
  data as (
    select id, dis, reg, dt, op, act
      from (
        select equipid id, district dis, region reg,
               to_char(operationdate, 'yyyy-mm') dt, 
               row_number() 
                   over (partition by equipid, trunc(operationdate, 'month') 
                   order by operationdate desc) rn, 
               operation op, nvl(equipactive, 0) act
          from t)
      where rn = 1 )
select mth, dis, reg, sum(act) cnt
  from (
    select id, mth, 
           nvl(dis, lag(dis) ignore nulls over (partition by id order by mth)) dis, 
           nvl(reg, lag(reg) ignore nulls over (partition by id order by mth)) reg,
           nvl(act, lag(act) ignore nulls over (partition by id order by mth)) act
      from calendar
      left join data partition by (id) on dt = to_char(mth, 'yyyy-mm') )
  group by mth, dis, reg
  having sum(act) > 0
  order by mth, dis, reg

这可能看起来很复杂,所以请先单独运行子查询,看看发生了什么。并测试 :) 希望这会有所帮助。

【讨论】:

  • 感谢您设置 DB Fiddle,这是超越。我在这里做了一个小更新:link 如果前 3 个项目是在 2012 年添加的,那么使用您的示例它们将不会在 2015 年 1 月出现。
  • 如果报告 2015 年,则不分析 2012 年的数据。要包含此类数据,我们必须对 2015 年之前的所有内容进行初始状态,并将其视为 2015-01 的第一次操作,首先进行联合。
猜你喜欢
  • 2022-06-14
  • 2012-04-08
  • 1970-01-01
  • 2019-01-15
  • 2016-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多