添加和增加日期和时间(Postgresql)

时间:2013-09-02 11:29:35

标签: sql postgresql date time increment

以下是一张表格,用于显示媒体播放的时间。所以基本上它有一个开始时间(starts),曲目的长度(clip_length),以及它何时结束(ends = starts + clip_length),最后是位置的轨道。

|starts              | ends                 |position   |file_id| clip_length
|2013-08-30 22:00:00 | 2013-08-30 22:03:08  |0          |16     |00:03:08.081768
|2013-08-30 22:03:08 | 2013-08-30 22:06:33  |1          |17     |00:03:25.436485
|2013-08-30 22:06:33 | 2013-08-30 22:09:07  |2          |7      |00:02:33.79968
|2013-08-30 22:09:07 | 2013-08-30 22:12:21  |3          |3      |00:03:14.020273
|2013-08-30 22:12:21 | 2013-08-30 22:15:31  |4          |8      |00:03:10.466689

我想要做的是添加一条记录,比如position =2,如下所示。我已经能够增加位置,但问题在于时间都搞砸了。

|starts              | ends                 |position   |file_id|clip_length
|2013-08-30 22:00:00 | 2013-08-30 22:03:08  |0          |16     |00:03:08.081768
|2013-08-30 22:03:08 | 2013-08-30 22:06:33  |1          |17     |00:03:25.436485
|2013-08-30 22:06:33 | 2013-08-30 22:09:07  |2          |7      |00:02:33.79968
|2013-08-30 22:06:33 | 2013-08-30 22:11:03  |3          |1      |00:04:30.006958
|2013-08-30 22:09:07 | 2013-08-30 22:12:21  |4          |3      |00:03:14.020273
|2013-08-30 22:12:21 | 2013-08-30 22:15:31  |5          |8      |00:03:10.466689

因此可以使用第一个开始时间..作为点00,并将clip_length添加到starts并保存在ends中,作为第一个。然后对于第二个使用第一个ends值作为开始并递归地执行此操作直到结束(在位置之后)。

提前感谢..

3 个答案:

答案 0 :(得分:3)

SQL Fiddle

update clip c
set
    starts = s.starts,
    ends = s.ends
from (
    select
        starts,
        starts + clip_length as ends,
        file_id,
        position
    from (
        select
            '2013-08-30 22:00:00'::timestamp
            + sum(clip_length) over(order by position)
            - clip_length as starts,
            clip_length,
            file_id,
            position
        from clip
    ) s
) s
where c.file_id = s.file_id

答案 1 :(得分:3)

您的数据模型非常糟糕。您要存储至少两条冗余信息。您需要startsfile_id以及clip_lengthendsposition中的任何一个;它们每个都可以相互计算。

现在您正在存储冗余数据,这会产生您现在遇到的问题,即数据内部不一致,它本身就存在冲突。

在这种情况下,听起来position是受信任的而其他人则不受信任。这就是我要做的事情:

SELECT 
  (SELECT min(starts) FROM Sometable)
    + COALESCE(
       sum(clip_length) OVER all_rows_but_last,
       INTERVAL '0' second
    )
  AS starts,
  (SELECT min(starts) FROM Sometable)
    + COALESCE(
       sum(clip_length) OVER all_rows_but_last,
       INTERVAL '0' second
    ) + clip_length
  AS ends, 
  position, 
  clip_length
FROM Sometable
WINDOW all_rows_but_last AS (ORDER BY position ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING);

请参阅:http://sqlfiddle.com/#!12/ca5fa/1

这里的原则是找到最低的开始 - 已知有效的开始 - 并且忽略以下结束并开始冗余和无用。相反,将先前持续时间的运行总计添加为开始,并将相同的运行总数加上当前间隔作为结束。

您会注意到这不是更新。那是因为我认为你应该这样做:

  • position更改为浮点值或大整数,因此在插入条目时无需重新编号。如果您在12之间添加某个内容,请将其设置为0.5。或者从1000020000等开始,以便您插入15000

  • 完全删除ends列。从starts + clip_length

  • 计算出来
  • starts移动到一个单独的表格中,该表格仅存储一次,用于一系列细分。从开始以来的先前剪辑的长度总和计算剪辑开始时间。

  • 将当前表重新定义为上述两个表的视图。

这对你的数据和你如何使用它做了很多猜测,但是你没有多说你正在做什么。

答案 2 :(得分:1)

with cte as (
    select
        '2013-08-30 22:00:00'::timestamp
         + sum(clip_length) over(order by position) as ends,
         file_id
    from clip
)
update clip as cl set
    starts = c.ends - cl.clip_length,
    ends = c.ends
from cte as c
where cl.file_id = c.file_id;

=>sql fiddle

实际上,你可以在你的桌子上没有开始和结束时间。您可以从表中删除此列并创建如下函数:

create or replace function clip_layout(_starts timestamp)
returns table(
    starts timestamp, ends timestamp,
    "position" int, file_id int,clip_length interval
)
as
$$
with cte as (
    select
        _starts + sum(clip_length) over(order by position) as ends,
        file_id, clip_length, position
    from clip
)
select
    ends - clip_length as starts,
    ends, position,
    file_id, clip_length
from cte
$$
language sql;

因此,您可以随时查看开始/结束时间:

select * from clip_layout('2013-08-30 22:00:00'::timestamp)

=>sql fiddle demo