以下是一张表格,用于显示媒体播放的时间。所以基本上它有一个开始时间(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
值作为开始并递归地执行此操作直到结束(在位置之后)。
提前感谢..
答案 0 :(得分:3)
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)
您的数据模型非常糟糕。您要存储至少两条冗余信息。您需要starts
和file_id
以及clip_length
,ends
或position
中的任何一个;它们每个都可以相互计算。
现在您正在存储冗余数据,这会产生您现在遇到的问题,即数据内部不一致,它本身就存在冲突。
在这种情况下,听起来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
更改为浮点值或大整数,因此在插入条目时无需重新编号。如果您在1
和2
之间添加某个内容,请将其设置为0.5
。或者从10000
,20000
等开始,以便您插入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;
实际上,你可以在你的桌子上没有开始和结束时间。您可以从表中删除此列并创建如下函数:
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)