表示过期记录
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
我需要存储连接到端口的关税。 所以,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