Java 查找时间范围内任何时间的平均活跃工人数

Java 查找时间范围内任何时间的平均活跃工人数,java,sql,algorithm,datetime,date-range,Java,Sql,Algorithm,Datetime,Date Range,TLDR:希望使用下面的SQL表获得某个时间范围内每个不同组的平均工作人员数(在任何时候)。通过使用SQL查询或将原始数据从SQL移动到java并在那里进行计算 我试图通过下表找出特定时间范围内(比如2019年5月8日至2019年4月9日)任何时候可用的一组(每组)工人的平均数量: CREATE TABLE workers( group VARCHAR(75) NOT NULL, worker_name VARCHAR(75) NOT NULL, times tstzrange NO

TLDR:希望使用下面的SQL表获得某个时间范围内每个不同组的平均工作人员数(在任何时候)。通过使用SQL查询或将原始数据从SQL移动到java并在那里进行计算

我试图通过下表找出特定时间范围内(比如2019年5月8日至2019年4月9日)任何时候可用的一组(每组)工人的平均数量:

CREATE TABLE workers(
  group VARCHAR(75) NOT NULL,
  worker_name VARCHAR(75) NOT NULL,
  times tstzrange NOT NULL, 
); 
为了帮助澄清该表是如何工作的:它表示属于特定工人组的工人机器。我知道,当时间字段(tstzrange)上有结束界限时,工作人员已离开组,否则,如果工作人员仍在组中,则时间是无限的。工作人员可以在任何时间内处于活动状态,“时间”可以跨越多天。只有在重新启动辅助进程或添加全新辅助进程时,才会添加新行。工人可以在两天之间保持活动状态,并且每天不创建新行

public class DateGroupKey {
  private String group;
  private LocalDate date;

  public DateGroupKey(String group, LocalDate date) {
      this.group = group;
      this.date = date; 
  }

  // Override equals and hash to be used as key for HashMap

}
使这一点更加困难的一个问题是,在一天的时间里,可能会有工人加入或离开该小组,有时会在一小时或更短的时间内加入或离开该小组。例如,一个时间范围内可能有100-120个工作者行,即使该时间范围内任何时间(我正在寻找的)的平均工作者数量应该是4。另外,我想要每个不同组的平均值。目前,我正在使用下面的查询来获取数据,将其映射到Java中的对象,然后从中构造一个解决方案

select worker_name, lower(times) as start, upper(times) as end, group
from workers
where times && tstzrange('2019-08-05', '2019-09-04')
大部分工作都是在Java中完成的,我在Java中绘制每个组的映射->属于该组的所有工作人员及其时间戳。然后,我通过查看这段时间内每天有多少工人在工作,然后在整个时间范围内对其进行平均,以找到这段时间内每个组中可用的工人的平均数量,来整合此列表。这似乎有点低效,而且不是所有组都能像预期的那样工作,我想知道我是否能够直接在SQL中(或者在java中有效地)以更好的方式完成这项工作。我已经研究这个问题有一段时间了,起初我认为它看起来很简单,但我正在努力找到更好的解决方案。希望有人在做这类事情方面有更多的经验,能给我一个很好的解决方案,以及是否应该直接在SQL中处理,或者是否需要一些java逻辑

这就是我从Java中的SQL获取数据到对象时使用的映射

public class WorkerMapping {

  private String group;
  private List<LocalDate> dates;

  public WorkerMapping(OffsetDateTime start, OffSetDateTime end, String group) {
    this.dates = start.toLocalDate().datesUntil(end.toLocalDate()).collect(Collectors.toList());
    this.group = group; 
  }

  // Getters and Setters
}
获取每组平均值的当前逻辑:


    public HashMap<String, Double> getAverage(List<WorkerMapping> rows)
    {
        HashMap<String, Double> workerAverage = new HashMap<>();
        // Treemap is used so keys can be processed in order, and all groups are together. 
        TreeMap<DateGroupKey, Integer> map = new TreeMap<>((a, b) -> a.getGroup().equals(b.getGroup()) ?
                a.getDate().compareTo(b.getDate()) : a.getGroup().compareTo(b.getGroup()));
        for (HostsRow row : rows)
        {
            for (LocalDate date : row.getDates()) {
                DateGroupKey key = new DateGroupKey(row.getGroup(), date);
                if (map.containsKey(key)) {
                    map.put(key, map.get(key) + 1);
                } else {
                    map.put(key, 1);
                }
            }
        }

        List<DateGroupKey> keys = new ArrayList<>(map.keySet());
        String currentGroup = keys.get(0).getGroup();
        int currentSum = 0;

        for (DateGroupKey key : keys ) {
            if (!key.getGroup().equals(currentGroup)) {
                workerAverage.put(currentGroup, Math.ceil(currentSum / 30.0));
                currentGroup = key.getGroup();
                currentSum = 0;
            }
            currentSum += map.get(key);
        }
        workerAverage.put(currentGroup, Math.ceil(currentSum / 30.0));
        return workerAverage;
    }

公共HashMap getAverage(列表行)
{
HashMap workerAverage=新HashMap();
//使用Treemap可以按顺序处理键,并且所有组都在一起。
TreeMap map=newtreemap((a,b)->a.getGroup().equals(b.getGroup())?
a、 getDate().compareTo(b.getDate()):a.getGroup().compareTo(b.getGroup());
用于(主机row行:行)
{
对于(LocalDate:row.getDates()){
DateGroupKey=新的DateGroupKey(row.getGroup(),date);
if(地图容器(图例)){
map.put(键,map.get(键)+1);
}否则{
地图放置(图例1);
}
}
}
List keys=newarraylist(map.keySet());
字符串currentGroup=keys.get(0.getGroup();
int currentSum=0;
用于(DateGroupKey:keys){
如果(!key.getGroup().equals(currentGroup)){
Workerage.put(currentGroup,Math.ceil(currentSum/30.0));
currentGroup=key.getGroup();
currentSum=0;
}
currentSum+=map.get(键);
}
Workerage.put(currentGroup,Math.ceil(currentSum/30.0));
返回平均工作时间;
}

我希望通过使用更好的sql查询或更高效的java,在一个时间范围内的任何时候都能收到一份从组到平均工人的映射。

我认为您的数据设置是错误的。如果工作人员被从组中删除,您将不得不知道这一点,因为组只是一个将要更改的单个字段。你必须记录轮班历史。或者该表是否实际包含工作班次而不是工人实体?@M.Prokhorov因为时间字段作为tstzrange给出,我知道工人已离开该组,因为该范围将有一个上限。否则,范围将是无限的。我将把这个问题也添加到问题中,以帮助澄清这一点。那么,这实际上是一个工作轮班吗?还有,这些在晚上会发生什么?那么,如果第二天的工人在同一组中会发生什么?在
工人中是否会有新记录?@M.Prokhorov工人代表的是工人机器,而不是实际工人。workers中的记录可以跨越几天甚至整个时间范围,并且可以整夜处于活动状态。每天都不会创建新记录,只有在结束后重新启动工作进程或启动全新工作进程时才会创建新记录。