Postgresql 在连续流程上创建截止日期

Postgresql 在连续流程上创建截止日期,postgresql,sql-insert,Postgresql,Sql Insert,我是一名实习生,正在为一些CNC机器指标进行数据采集,我有点被一个特定的查询所困扰,上周才开始使用sql,所以如果这是一个愚蠢的问题,请原谅我 如果机器在23:59之前运行(状态=开),并且我想收集当天的机器小时数,则没有注销时间,因为状态=关闭列尚未记录,因此我无法收集该机器数据。为了解决这个问题,我想记录一个23:59:59的状态关闭时间,然后创建一个新行,该行具有相同的实体ID,状态为“on time of day+1,00:00:01” 这是我到目前为止写的,我错在哪里?我应该使用什么样

我是一名实习生,正在为一些CNC机器指标进行数据采集,我有点被一个特定的查询所困扰,上周才开始使用sql,所以如果这是一个愚蠢的问题,请原谅我

如果机器在23:59之前运行(状态=开),并且我想收集当天的机器小时数,则没有注销时间,因为状态=关闭列尚未记录,因此我无法收集该机器数据。为了解决这个问题,我想记录一个23:59:59的状态关闭时间,然后创建一个新行,该行具有相同的实体ID,状态为“on time of day+1,00:00:01”

这是我到目前为止写的,我错在哪里?我应该使用什么样的触发器、插入、程序、案例等组合?欢迎提出任何建议,我已经试着看了一些参考资料,希望第一部分看起来像这样

CASE
  WHEN min(stoff.last_changed) IS NULL 
        AND now() = '____-__-__ 23:59:59.062538+13'
    THEN min(stoff.last_changed) IS now()
  ELSE min(stoff.last_changed)
END

<> p>我知道这只是第一个组件,但是它适合于一个更大的选择在一个视图中使用,让我知道如果我需要发布任何其他的< /p> 这是一个相当复杂的查询,因为有几个可能需要考虑的可能性(考虑到CNC机器的物理设置,这些可能并不都适用:

  • 机器可能在午夜运行,因此您需要“插入”午夜开始时间(并将午夜视为前一天的停止时间)
  • 机器可能整天都在运行(因此表中根本没有当天的记录)
有许多方法可以实现这一点;我选择了一种我认为最容易理解的方法(并且避免了窗口函数)。响应确实使用,但我认为这些方法很容易理解(它实际上只是一个查询链;每个查询都使用前一个查询的结果)

让我们设置一些示例数据:

create table states (
  entity_id int,
  last_changed timestamp,
  state bool
  );

insert into states(entity_id, last_changed, state) values
(1, '2019-11-26 01:00', false),
(1, '2019-11-26 20:00', true),
(1, '2019-11-27 01:00', false),
(1, '2019-11-27 02:00', true),
(1, '2019-11-27 22:00', false);
现在查询(它没有看起来那么糟糕!):


您可以在一个查询中完成这一切(不需要触发器、插入等),但对于一天中打开/关闭多次的设备的查询计算运行时,我通常使用窗口函数(相当高级的SQL)。这可能不是必需的;它实际上取决于您可用的数据。如果没有更多的上下文,您当前的代码很难理解;也许您可以添加足够的详细信息,使工作示例为初学者提供上述代码的修改版本(它提供了一个结果,但它是错误的!)。非常感谢@britsThanks!我将SQL放在那里,它直接处理我们的数据库,实际上只是将实体id与开/关状态列配对,并比较时间戳之间的时间(给出状态更改之间经过的时间)。我想实现的是创建一个通过day刷新的表,换句话说,如果一台机器在3天内没有报告关闭状态的更改,那么它将在3行上有条目,这些条目都代表某一天机器正在运行。希望这有点清楚,这很容易理解,再次感谢您选择t是时候帮忙了!我最后向一位同事寻求帮助,结果发现我们想出了与你大致相同的方法。对于任何有类似问题的人,我们写了一个表格,列出了工作日、工作时间(即有员工与无员工)的所有可能组合并将其交叉连接到我们的表中,最后一个_被更改,将任何持续时间都归类为表中可能的行之一
 -- Lets start with a range of dates that you want the report for (needed because its possible that there are 
 -- no entries at all in the states table for a particular date)    
with date_range as (
    select i::date from generate_series('2019-11-26', '2019-11-29', '1 day'::interval) i
),
-- Get all combinations of machine (entity_id) and date
allMachineDays as (
    select  distinct states.entity_id, date_range.i as started
    from 
    states cross join date_range),
-- Work out what the state at the start of each day was (if no earlier state available then assume false)
stateAtStartOfDay as (
    select 
        entity_id, started, 
        COALESCE(
            (
                select state 
                from states 
                where states.entity_id = allMachineDays.entity_id 
                    and states.last_changed<=allMachineDays.started 
                order by states.last_changed desc limit 1
            )
            ,false) as state
   from allMachineDays
)
,
-- Now we can add in the state at the start of each day to the other state changes
statesIncludingStartOfDay as (
    select * from stateAtStartOfDay 
    union 
    select * from states
),
-- Next we add the time that the state changed
statesWithEnd as (
    select
        entity_id, 
        state,
        started,
        (
            select started from statesIncludingStartOfDay substate
             where 
             substate.entity_id = states.entity_id and 
             substate.started  > states.started
             order by started asc
             limit 1
         ) as ended
    from 
    statesIncludingStartOfDay states
)
-- finally lets work out the duration
select
    entity_id, 
    state,
    started,
    ended,
    ended - started as duration
from 
    statesWithEnd states
where 
    ended is not null -- cut off the last midnight as its no longer needed
order by entity_id,started
with date_range as (
    select i::date from generate_series('2019-11-26', '2019-11-29', '1 day'::interval) i
)
select * from date_range