1

次の表( validity_periodという名前を付けましょう):

-------------------------------
id | valid_from | まで有効
-------------------------------
1 2012-11-12 2012-12-02
2 2012-12-03 NULL
3 2012-12-15 2012-12-21

valid_from はnull可能ではありません。valid_untilはnull可能ですが、nullである必要はありません)

次に、今日(2012-12-19)に有効なエントリを確認します。論理的な観点からは、エントリ3である必要があります。これは、エントリが互いに重複する可能性がありますが、1日に有効なエントリは1つだけであるためです。(2012-12-22では、有効なエントリ2である必要があります。)
すべてのエントリにvalid_untilを含めることができますが、valid_untilNULLであるエントリは複数存在できないことに注意してください。

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

Explain計画をチェックして、それがより大きなデータ・セットの改善であるかどうかを確認してください。

編集:「最後の」レコードが今日より前の日付まで有効であり、行が返されない状況が発生する可能性がある場合は、次のことを試してください。

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

あなたの質問はあまり明確ではありません。null以外の一致が複数存在する可能性はありますvalid_untilか?どちらを選びますか?何を返したいですか?1列?いくつかの?全て?

とにかく、ソリューションとして投稿したものは次のように簡略化できます。

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 に答える