表示过期记录

Representing expiring records

我需要存储连接到端口的关税。 所以,table 可以看起来像这样:

create table tariffs(
    int NOT NULL AUTO_INCREMENT,
    price decimal(12,2),
    expiry bigint(11)
)

expiry 表示特定关税到期的时间戳。 所以我可能有这样的数据:

id | price    | expiry
1  | 11.00    | 30/Jan/2022
2  | 12.00    | 30/Feb/2022
3  | 13.00    | 30/Mar/2022
4  | 14.00    | 30/Apr/2022
5  | 15.00    | null

在这种情况下,ID 5 尚未过期,这意味着它是最新的。 (我意识到我把日期放在那里,而不是时间戳;我这样做是为了更容易阅读)

我遇到的问题是在给定特定日期时找出使用哪种关税的逻辑。 在一个理想的世界中,如果 5 是“无限”,我可以只做 WHERE expiry > date_apply limit 1——但是,我没有那么奢侈,因为 date_apply 根本不会返回。

我可以为“当前”条目的 expiry 分配一个非常大的数字。无论如何,它都会使查询工作。但是……感觉不对。

有人建议为每个关税使用两个字段,“从”和“到”,告诉我否则查询将是一场噩梦。我开始明白他们的意思了……但我担心运营商可能不情愿地在关税时间表上出现“漏洞”,这很难避免。

我应该如何组织我的 table,我应该如何查询它?这里的最佳做法是什么?

SELECT COALESCE(t2.price, t1.price) AS price
FROM (SELECT price FROM tariffs WHERE expiry IS NULL LIMIT 1) AS t1
LEFT OUTER JOIN (SELECT price FROM tariffs WHERE expiry > ? ORDER BY expiry DESC LIMIT 1) AS t2

演示:https://www.db-fiddle.com/f/wykqR5X7B9S424AWkA4aQy/1

如果您至少有一个未过期的关税,则第一个子查询绑定到 return 1 行。

如果输入日期太晚,第二个子查询可能不会 return 1 行。所以我将此连接更改为 LEFT OUTER JOIN。如果到期条件没有匹配的行,子查询将 return 没有行,外连接将用 NULL 替换这些行。

因此,如果 t2.* 为 NULL,则 COALESCE() 默认为 t1.price 中未过期的值。

你可以把最终价格留一个expiry null,我们可以根据当时需要的逻辑使用coalesce来赋值。
在这里,我们仅从过期的关税和到期 = null 的关税开始。我们创建一个视图,将到期时间显示为 undefined。然后我们添加一个有效的 tarif,它由同一视图正确返回。

create table tariffs(
    id int NOT NULL PRIMARY KEY AUTO_INCREMENT,
    price decimal(12,2),
    expiry date);
insert into tariffs (price,expiry) values (11,'2022-01-30'),(12,null);
create view current_tarif as
select id, price, coalesce(expiry,'undefined') expiry
from tariffs
where coalesce(expiry,'3000-12-31') > curdate() 
order by coalesce(expiry,'3000-12-31')
limit 1;
select * from current_tarif;
id | price | expiry   
-: | ----: | :--------
 2 | 12.00 | undefined
insert into tariffs (price,expiry) values (15,'2022-12-30');
select * from current_tarif;
id | price | expiry    
-: | ----: | :---------
 3 | 15.00 | 2022-12-30

db<>fiddle here

使用 OLAP 函数构建您的有效期和到期时间dates/timestamps。

WITH                                                                                                                                                                                                                                   
indata(id,price,expiry) AS (
          SELECT 1,11.00,DATE '30-Jan-2022'
UNION ALL SELECT 2,12.00,DATE '28-Feb-2022'
UNION ALL SELECT 3,13.00,DATE '30-Mar-2022'
UNION ALL SELECT 4,14.00,DATE '30-Apr-2022'
UNION ALL SELECT 5,15.00,NULL
)
,
enriched AS (
  SELECT 
    id
  , price
  , LAG(NVL(expiry, '9999-12-31'),1,'0001-01-01') OVER(ORDER BY id)  AS   validity
  , NVL(expiry, '9999-12-31')                    AS expiry
  FROM indata
  -- chk  id | price |  validity  |   expiry   
  -- chk ----+-------+------------+------------
  -- chk   1 | 11.00 | 0001-01-01 | 2022-01-30
  -- chk   2 | 12.00 | 2022-01-30 | 2022-02-28
  -- chk   3 | 13.00 | 2022-02-28 | 2022-03-30
  -- chk   4 | 14.00 | 2022-03-30 | 2022-04-30
  -- chk   5 | 15.00 | 2022-04-30 | 9999-12-31
)
SELECT
  price
FROM enriched
WHERE '2022-04-22' >= validity
  AND '2022-04-22  < expiry
;

您可以编写 CASE WHEN 语句并将 expiry 列更改为最大值 999-12-31(253402270022) if expiry is null 然后排序并获取最大到期时间。那么就可以执行条件expiry > date_apply

WITH maxTariffs AS
(SELECT  id, 
  (CASE
    WHEN expiry IS NULL 
        THEN 253402270022
    ELSE expiry    
END) AS expiry
FROM tariffs)   
 
SELECT * FROM tariffs WHERE  id IN (SELECT id FROM maxTariffs WHERE expiry > DATE_APPLY ORDER BY expiry ASC )  LIMIT 1 

演示在 DBfiddle