我有一个带有唯一日期时间字段的 postgres 表。我想使用/创建一个函数,该函数将日期时间值作为参数,并返回与传递的日期时间值最接近的日期时间相对(但不等于)的行 ID。第二个参数可以在传递值之前或之后指定。
理想情况下,本机日期时间函数的某种组合可以处理此要求。否则它必须是一个自定义函数。
问题:查询一组行的相对日期时间的方法是什么?
我有一个带有唯一日期时间字段的 postgres 表。我想使用/创建一个函数,该函数将日期时间值作为参数,并返回与传递的日期时间值最接近的日期时间相对(但不等于)的行 ID。第二个参数可以在传递值之前或之后指定。
理想情况下,本机日期时间函数的某种组合可以处理此要求。否则它必须是一个自定义函数。
问题:查询一组行的相对日期时间的方法是什么?
select id, passed_ts - ts_column difference
from t
where
passed_ts > ts_column and positive_interval
or
passed_ts < ts_column and not positive_interval
order by abs(extract(epoch from passed_ts - ts_column))
limit 1
passed_ts
是时间戳参数,positive_interval
是一个布尔参数。如果为 true,则仅时间戳列低于传递的时间戳的行。如果为假,则相反。
您希望 select 语句的第一行以降序(或升序)顺序生成低于(或高于)给定日期时间的所有行。
函数体的伪代码:
SELECT id
FROM table
WHERE IF(@above, datecol < @param, datecol > @param)
ORDER BY IF (@above. datecol ASC, datecol DESC)
LIMIT 1
但是,这是行不通的:不能以排序方向为条件。
第二个想法是做两个查询,然后选择:
SELECT *
FROM (
(
SELECT 'below' AS dir, id
FROM table
WHERE datecol < @param
ORDER BY datecol DESC
LIMIT 1
) UNION (
SELECT 'above' AS dir, id
FROM table
WHERE datecol > @param
ORDER BY datecol ASC
LIMIT 1)
) AS t
WHERE dir = @dir
使用日期时间列上的索引应该很快。
-- test rig
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE lutser
( dt timestamp NOT NULL PRIMARY KEY
);
-- populate it
INSERT INTO lutser(dt)
SELECT gs
FROM generate_series('2013-04-30', '2013-05-01', '1 min'::interval) gs
;
DELETE FROM lutser WHERE random() < 0.9;
--
-- The query:
WITH xyz AS (
SELECT dt AS hh
, LAG (dt) OVER (ORDER by dt ) AS ll
FROM lutser
)
SELECT *
FROM xyz bb
WHERE '2013-04-30 12:00' BETWEEN bb.ll AND bb.hh
;
结果:
NOTICE: drop cascades to table tmp.lutser
DROP SCHEMA
CREATE SCHEMA
SET
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "lutser_pkey" for table "lutser"
CREATE TABLE
INSERT 0 1441
DELETE 1288
hh | ll
---------------------+---------------------
2013-04-30 12:02:00 | 2013-04-30 11:50:00
(1 row)
将其包装成一个函数留给读者作为练习
更新:这是第二个带有夹层不存在技巧(TM)的:
SELECT lo.dt AS ll
FROM lutser lo
JOIN lutser hi ON hi.dt > lo.dt
AND NOT EXISTS (
SELECT * FROM lutser nx
WHERE nx.dt < hi.dt
AND nx.dt > lo.dt
)
WHERE '2013-04-30 12:00' BETWEEN lo.dt AND hi.dt
;
简单地使用-。
假设您有一个带有属性 Key、Attr 和 T 的表(带有或不带有时区的时间戳):
you can search with
select min(T - TimeValue) from Table where (T - TimeValue) > 0;
这会给你主要的区别。您可以将此值与同一个表的连接结合起来,以获得您感兴趣的元组:
select * from (select *, T - TimeValue as diff from Table) as T1 NATURAL JOIN
( select min(T - TimeValue) as diff from Table where (T - TimeValue) > 0) as T2;
应该这样做
--dmg
尝试类似:
SELECT *
FROM your_table
WHERE (dt_time > argument_time and search_above = 'true')
OR (dt_time < argument_time and search_above = 'false')
ORDER BY CASE WHEN search_above = 'true'
THEN dt_time - argument_time
ELSE argument_time - dt_time
END
LIMIT 1;
您必须使用 where 条件将表连接到自身,以查找基表行的日期时间和连接表行的日期时间之间的最小非零(负或正)间隔。在该日期时间列上有一个索引会很好。
PS您还可以查找前一个的 max() 或后续的 min()。