我一直在处理将指标分为几个范围的问题。为了给您一些背景信息,让我们以这个示例为例,其中每个客户有一定数量的订单。现在,客户可以订购n个产品。让我们根据订单数量为客户提供一定的折扣。折扣基于分层模型提供。为了简化起见,我将省略多个产品类别。这是表格的一些示例。
订单表
Customer | order_no
----------------------------
Customer1 | 400
Customer2 | 1200
Customer3 | 40
Customer4 | 2000
Customer5 | 700
分层定价表
Tier | lower_th | higer_th | price |
--------------------------------------
Tier1 | 0 | 250 | 50 |
TIer2 | 251 | 500 | 45 |
Tier3 | 501 | 1000 | 40 |
TIer4 | 1001 | 10000 | 30 |
示例1 :我希望能够向Customer1收取250笔订单的50美元费用,以及其余150种产品(共400笔)的45美元费用。
示例2:我希望能够向Customer5收取250个订单的50美元费用,另外250个订单的45美元费用,其余700个产品中的其余200个产品的费用为40美元。
如何在PostgreSQL中实现这一目标?对于Customer1,我的输出需要为以下内容。拆分订单总数并将其加入定价层以获取相应金额的最佳方法是什么?
Customer | order_no | charges |
--------------------------------
Customer1 | 250 | 50 |
Customer1 | 150 | 45 |
答案 0 :(得分:1)
您可以将层视为间隔。
两个时间间隔[a1, b1]
和[a2, b2]
相交
a1 <= b2 AND b1 >= a2
订单数是另一个始终从1开始的时间间隔。
您的两个时间间隔是:等级[lower_th, higer_th]
和订单[1, order_no]
。
查询是使用此交集表达式的简单联接:
SELECT *
,CASE WHEN O.order_no > T.higer_th
THEN T.higer_th - T.lower_th + 1 -- full tier
ELSE O.order_no - T.lower_th + 1
END AS SplitOrderNumbers
FROM
Orders AS O
INNER JOIN Tiers AS T
-- ON 1 <= T.higer_th AND O.order_no >= T.lower_th
ON O.order_no >= T.lower_th
ORDER BY
O.Customer
,T.lower_th
;
您真的不需要1 <= T.higer_th
部分,因为它始终是真实的,因此表达式变得简单O.order_no >= T.lower_th
。
此外,通常最好将间隔存储为[closed; open)
。它通常可以简化算术运算,这与大多数编程语言的数组索引从0开始而不是从1开始的原因类似。您的间隔似乎为[closed; closed]
。在这种情况下,您需要将lower_th
设置为1
,而不是0
,并在计算中使用+1
。
通过调整样本数据,此查询将产生以下结果:
+-----------+----------+-------+----------+----------+-------+-------------------+
| Customer | order_no | Tier | lower_th | higer_th | price | SplitOrderNumbers |
+-----------+----------+-------+----------+----------+-------+-------------------+
| Customer1 | 400 | Tier1 | 1 | 250 | 50.00 | 250 |
| Customer1 | 400 | Tier2 | 251 | 500 | 45.00 | 150 |
| Customer2 | 1200 | Tier1 | 1 | 250 | 50.00 | 250 |
| Customer2 | 1200 | Tier2 | 251 | 500 | 45.00 | 250 |
| Customer2 | 1200 | Tier3 | 501 | 1000 | 40.00 | 500 |
| Customer2 | 1200 | Tier4 | 1001 | 10000 | 30.00 | 200 |
| Customer3 | 40 | Tier1 | 1 | 250 | 50.00 | 40 |
| Customer4 | 2000 | Tier1 | 1 | 250 | 50.00 | 250 |
| Customer4 | 2000 | Tier2 | 251 | 500 | 45.00 | 250 |
| Customer4 | 2000 | Tier3 | 501 | 1000 | 40.00 | 500 |
| Customer4 | 2000 | Tier4 | 1001 | 10000 | 30.00 | 1000 |
| Customer5 | 700 | Tier1 | 1 | 250 | 50.00 | 250 |
| Customer5 | 700 | Tier2 | 251 | 500 | 45.00 | 250 |
| Customer5 | 700 | Tier3 | 501 | 1000 | 40.00 | 200 |
+-----------+----------+-------+----------+----------+-------+-------------------+
答案 1 :(得分:1)
对于定价数据,我将使用这样的表格来简化数据维护
create table pricing_data
(
high_limit int,
price numeric
);
视图将使用窗口功能为您提供所需的时间间隔:
create view pricing as
select coalesce(lag(high_limit) over (order by high_limit), 0) as last_limit,
high_limit, price
from pricing_data;
这简化了进入定价层的突破:
select o.customer,
least(o.order_no - p.last_limit, p.high_limit - p.last_limit) as order_no,
p.price as charges
from orders o
join pricing p on p.last_limit < o.order_no
order by o.customer, p.price desc
;
结果:
customer order_no charges
Customer1 250 50
Customer1 150 45
Customer2 250 50
Customer2 250 45
Customer2 500 40
Customer2 200 30
Customer3 40 50
Customer4 250 50
Customer4 250 45
Customer4 500 40
Customer4 1000 30
Customer5 250 50
Customer5 250 45
Customer5 200 40
14 rows