1

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

-------------------------------------------
编号 | 有效来自 | 有效_直到
-------------------------------------------
1 2012-11-12 2012-12-02
2 2012-12-03 空
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

4 回答 4

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
        ;
于 2012-12-20T00:05:50.763 回答
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

于 2012-12-19T17:38:30.813 回答
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)
于 2012-12-19T17:43:48.427 回答
0

你的问题不是很清楚。non-null 可以有多个匹配项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;
于 2012-12-20T11:05:31.950 回答