SQL - 查找与当前日期匹配的条目

时间:2012-12-19 17:21:03

标签: python sql postgresql date sqlalchemy

下表(我们将其命名为 validity_period ):

-------------------------------
id | valid_from  | valid_until
-------------------------------
1    2012-11-12    2012-12-02
2    2012-12-03    NULL
3    2012-12-15    2012-12-21

valid_from 不可为空; valid_until 可以为空,但不必为空)

现在我想找出今天哪个条目有效(2012-12-19)。从逻辑视图来看,它必须是条目3,因为条目可以相互重叠,但一天只有一个条目有效。 (在2012-12-22,它必须是有效的第2项。)
请注意,所有条目都可以包含 valid_until ,但 valid_until 为NULL的条目不能超过一个。

我如何在SQL查询中执行此操作? (如果可能在SQLAlchemy中,但我也可以自己从原始SQL翻译它)

(我正在使用PostgreSQL 9.1)

编辑:这是我的最终解决方案。感谢所有贡献者!

SELECT * 
    FROM validity_period 
    WHERE valid_from <= CURRENT_DATE AND 
          valid_until >= CURRENT_DATE
UNION
SELECT * 
    FROM validity_period 
    WHERE valid_from <= CURRENT_DATE AND 
          valid_until IS NULL
ORDER BY valid_from DESC 
LIMIT 1;

4 个答案:

答案 0 :(得分:1)

您可以使用WINDOW函数(例如滞后或引​​导)来引用上一个/下一个记录,并限制“打开”间隔:

DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

CREATE TABLE daterange
        ( id INTEGER NOT NULL
        , valid_from  DATE NOT NULL
        , valid_until DATE
        );
INSERT INTO daterange (id, valid_from, valid_until) VALUES
 (1, '2012-11-12', '2012-12-02' )
,(2, '2012-12-03', NULL)
,(3, '2012-12-15', '2012-12-21' )
,(4, '2012-12-22', NULL )
        ;

-- The CTE is for convenience; could be a subquery or view
WITH magic AS (
        SELECT dr.id
        , dr.valid_from
        , COALESCE(dr.valid_until , lead(valid_from) OVER ww) AS valid_until
        FROM daterange dr
        WINDOW ww AS (ORDER BY dr.valid_from )
        )
SELECT *
FROM magic ma
WHERE now() BETWEEN ma.valid_from AND ma.valid_until
        ;

答案 1 :(得分:0)

尝试这样的事情:

SELECT  *
FROM    validity_period
WHERE   valid_from <= current_date
        AND valid_to >=current_date    
UNION 

--Gets the last instance where valid_until is null
SELECT * 
FROM validity_period 
WHERE   valid_from <= current_date
        AND valid_to IS NULL
ORDER BY id DESC LIMIT 1 

如果您想要第一个空字段而不是最后一个空字段,只需删除DESC

答案 2 :(得分:0)

作为示例,valid_until在您提供的数据中在逻辑上是冗余的,如果存在valid_from上的索引并且PostgreSQL将执行降序索引扫描,则可以使用此逻辑获得更快的结果:

select   *
from     validity_period
where    valid_from <= current_date
order by valid_from desc
limit    1

检查解释计划,看看它是否是对较大数据集的改进。

编辑:如果可能存在“最后”记录在今天之前有效的直到日期的情况,其中没有要返回的行,请尝试:

select   most_recent_record.*
from     (
         select   *
         from     validity_period
         where    valid_from <= current_date
         order by valid_from desc
         limit    1) most_recent_record
where    coalesce(most_recent_record.valid_until,current_date) <= current_date

最后一个谓词可能更好地读作:

where    not (most_recent_record.valid_until > current_date)

答案 3 :(得分:0)

你的问题不是很清楚。可以与非空valid_until匹配多个匹配项吗?选哪个?你想要什么回报?一栏?一些?所有?

无论如何,您发布的解决方案可以简化为:

SELECT * 
FROM   validity_period 
WHERE  valid_from  <= now()::date
AND   (valid_until >= now()::date OR valid_until IS NULL) -- parenthesis needed!
ORDER  BY valid_from DESC 
LIMIT  1;