用于验证日期范围的SQL索引

用于验证日期范围的SQL索引,sql,postgresql,Sql,Postgresql,我正在为一个案例建模,在这个案例中,一批批产品到达并随着时间的推移而消耗 数据如下所示: 批量单位 每批产品都以一定数量开始,并随着时间的推移而消耗 我想确保任何负值总是在每个批次的初始量(正值)之后 为此,我使用了以下要点索引: alter table batch_units add constraint batch_units_date_overlap_check exclude using gist ( batch_id with =, ( case when quanti

我正在为一个案例建模,在这个案例中,一批批产品到达并随着时间的推移而消耗

数据如下所示:

批量单位 每批产品都以一定数量开始,并随着时间的推移而消耗

我想确保任何负值总是在每个批次的初始量(正值)之后

为此,我使用了以下要点索引:

alter table batch_units
add constraint batch_units_date_overlap_check
exclude using gist (
  batch_id with =,
  (
    case when quantity >= 0
      then daterange('-infinity'::date, date, '()')
      else daterange(date, date, '[]')
    end
  ) with &&
);
这种方法几乎适用于所有情况,但不允许在同一天从同一批产品中取出两次。如果考虑到这一点,这将是理想的


我不确定我是否正确处理了这个问题。有人有什么建议吗?

如果您想找到有效的批次,即不是以负数开头的批次,您可以使用以下逻辑:

SELECT DISTINCT batch_id
FROM batch_units bu1
WHERE
    quantity > 0 AND
    NOT EXISTS (SELECT 1 FROM batch_units bu2
                WHERE bu2.batch_id = bu1.batch_id AND bu2.date < bu1.date AND
                      bu2.quantity < 0);

这应该允许Postgres只需扫描
batch\u units
表,然后根据索引快速查找每条记录。

对于
batch\u id=1
和日期
2020-01-01
,我们如何真正知道负数是否真的首先出现?请注意,SQL表中没有顺序;如果你给我们看这个订单,我们需要一些专栏来提供订单。我明白你的意思,我这方面有点输入错误。假设第一个负数至少在第二天是合理的-这个限制可以。这可以作为约束或索引实现吗?@J3Y我想你可能需要使用触发器来获得你想要的上面的逻辑。但是,除了我发布的内容之外,也许还有其他方法可以做到这一点。谢谢,我认为现在我们将保留约束条件,因为它更简单-尽管它有一个限制,即两个负值不能有相同的日期。如果我们以后需要更复杂的验证,那么我们可以迁移到触发器验证。
SELECT DISTINCT batch_id
FROM batch_units bu1
WHERE
    quantity > 0 AND
    NOT EXISTS (SELECT 1 FROM batch_units bu2
                WHERE bu2.batch_id = bu1.batch_id AND bu2.date < bu1.date AND
                      bu2.quantity < 0);
CREATE INDEX idx ON batch_units (batch_id, date, quantity);