gpt4 book ai didi

sql - 如何使用 PostgreSQL 计算分层定价

转载 作者:行者123 更新时间:2023-11-29 13:13:42 25 4
gpt4 key购买 nike

我正在尝试计算某些住宿的分级费率。假设我们有一个特性的每周、半周和每天的费率。

period_name | nights | rate
-------------------------------------
WEEK | 7 | 100
HALFWEEK | 3 | 50
DAY | 1 | 25

我如何使用总夜数查询此数据并分割符合条件的时间段(从最长到最短)?一些示例结果

10 晚

我们将 10 分成(7 天)+(3 天)。 7 天将按周费率 (100)。 3 天将按半周费率 (50)。在这里它符合 (1 WEEK @ 100) + (1 HALFWEEK @ 50)

period_name | nights | rate | num | subtotal
----------------------------------------------
WEEK | 7 | 100 | 1 | 100
HALFWEEK | 3 | 50 | 1 | 50

4 晚

我们将 4 分成(3 天)+(1 天)。 3 天将按半周费率 (50)。 1 天将按 DAY 费率 (25) 计算。在这里它符合 (1 HALFWEEK @ 50) + (1 DAY @ 25)

period_name | nights | rate | num | subtotal
----------------------------------------------
HALFWEEK | 3 | 50 | 1 | 50
DAY | 1 | 25 | 1 | 25

16 晚

我们将 16 分解为(14 天)+(2 天)。 14 天将采用周率(乘以 2),(100 * 2)。 2 天将按天费率 (2 x 25)。在这里它符合 (2 WEEK @ 100) + (2 DAY @ 25)

period_name | nights | rate | num | subtotal
----------------------------------------------
WEEK | 7 | 100 | 2 | 200
DAY | 1 | 25 | 2 | 50

我考虑过使用 lag窗口函数,但现在确定我将如何跟踪上一期间已经应用的天数。

最佳答案

您可以使用 CTE RECURSIVE 查询来执行此操作。

http://sqlfiddle.com/#!17/0ac709/1

等级表(可动态扩展):

id  name       days  rate  
-- --------- ---- ----
1 WEEK 7 100
2 DAYS 1 25
3 HALF_WEEK 3 50
4 MONTH 30 200

天数据:

id  num  
-- ---
1 10
2 31
3 30
4 19
5 14
6 108
7 3
8 5
9 1
10 2
11 7

结果:

num_id  num  days                                             total_price  
------ --- ----------------------------------------------- -----------
1 10 {"MONTH: 0","WEEK: 1","HALF_WEEK: 1","DAYS: 0"} 150
2 31 {"MONTH: 1","WEEK: 0","HALF_WEEK: 0","DAYS: 1"} 225
3 30 {"MONTH: 1","WEEK: 0","HALF_WEEK: 0","DAYS: 0"} 200
4 19 {"MONTH: 0","WEEK: 2","HALF_WEEK: 1","DAYS: 2"} 300
5 14 {"MONTH: 0","WEEK: 2","HALF_WEEK: 0","DAYS: 0"} 200
6 108 {"MONTH: 3","WEEK: 2","HALF_WEEK: 1","DAYS: 1"} 875
7 3 {"MONTH: 0","WEEK: 0","HALF_WEEK: 1","DAYS: 0"} 50
8 5 {"MONTH: 0","WEEK: 0","HALF_WEEK: 1","DAYS: 2"} 100
9 1 {"MONTH: 0","WEEK: 0","HALF_WEEK: 0","DAYS: 1"} 25
10 2 {"MONTH: 0","WEEK: 0","HALF_WEEK: 0","DAYS: 2"} 50
11 7 {"MONTH: 0","WEEK: 1","HALF_WEEK: 0","DAYS: 0"} 100

想法:

首先我使用这个查询来计算一个值 (19) 的结果:

SELECT 
days / 7 as WEEKS,
days % 7 / 3 as HALF_WEEKS,
days % 7 % 3 / 1 as DAYS
FROM
(SELECT 19 as days) s

在这里您可以看到以整数除法终止的模块运算的递归结构。因为应该需要一个更通用的版本,所以我考虑了一个递归版本。使用 PostgreSQL WITH RECURSIVE 子句,这是可能的

https://www.postgresql.org/docs/current/static/queries-with.html

这就是最后的查询

WITH RECURSIVE days_per_tier(row_no, name, days, rate, counts, mods, num_id, num) AS (
SELECT
row_no,
name,
days,
rate,
num.num / days,
num.num % days,
num.id,
num.num
FROM (
SELECT
*,
row_number() over (order by days DESC) as row_no -- C
FROM
testdata.tiers) tiers, -- A
(SELECT id, num FROM testdata.numbers) num -- B
WHERE row_no = 1

UNION

SELECT
days_per_tier.row_no + 1,
tiers.name,
tiers.days,
tiers.rate,
mods / tiers.days, -- D
mods % tiers.days, -- E
days_per_tier.num_id,
days_per_tier.num
FROM
days_per_tier,
(SELECT
*,
row_number() over (order by days DESC) as row_no
FROM testdata.tiers) tiers
WHERE days_per_tier.row_no + 1 = tiers.row_no
)
SELECT
num_id,
num,
array_agg(name || ': ' || counts ORDER BY days DESC) as days,
sum(total_rate_per_tier) as total_price -- G
FROM (
SELECT
*,
rate * counts as total_rate_per_tier -- F
FROM days_per_tier) s
GROUP BY num_id, num
ORDER BY num_Id

WITH RECURSIVE 包含递归的起点 UNION 的递归部分。起点只是获得层级 (A) 和数字 (B)。为了根据天数对层进行排序,我添加了行数(C;仅当相应的 ID 与我的示例中的顺序不正确时才需要。如果您添加另一个层,可能会发生这种情况)。

递归部分取上一个SELECT结果(存储在days_per_tier中),计算下一个余数和整数除法(D,E)。所有其他列仅用于保存原始值(负责递归本身的递增行计数器除外)。

递归后,计数和比率相乘 (F),然后按生成总和 (G) 的原始编号 id 分组

编辑:添加了速率函数和 sqlfiddle 链接。

关于sql - 如何使用 PostgreSQL 计算分层定价,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51699815/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com