如何 select 汇总折扣百分比和固定金额?
How to select aggregate discount percentages and flat amount?
我有一个场景,我需要汇总 n 个折扣以获得总折扣。每次折扣必须扣除之前的折扣。
例如: 我有一个 200 卢比的订单。 (金额总和)我有多张代金券。第一个让我享受 15% 的折扣,200-(200*(15/100)) = 170。
然后我们有第二张价值 10 卢比的代金券,170-(10) = 160。
顺序很重要,因此还有一个字段记录应用折扣的顺序。
下面是table:
- 订单
id order_id productId amount
1 1 5 160
2 1 9 40
所以没有折扣的总金额是:200 卢比
- 折扣
id order_id seq type amt
1 1 1 Per (%) 15
2 1 3 Flat 10
因此,折扣金额为:((200*(15/100)))
30 + 10 = 40 .
所以我尝试用 CTE 编写 SQL 查询,但它没有给出预期的输出:
WITH recursive cte_calctotalamount AS
(
SELECT order_id,
sum(amount) AS totalamount
FROM ORDER
WHERE order_id=1
GROUP BY order_id ),
cte_totaldiscountamount AS
(
SELECT i.order_id,
i.seq,
i.amt,
ta.totalamount AS totalamount,
CASE
WHEN i.type='Flat' THEN i.amt
WHEN i.type='Per' THEN (ta.totalamount * (i.amt/100))
END totaldiscountedamount,
(totalamount- (
CASE
WHEN i.type='Flat' THEN i.amt
WHEN i.type='Per' THEN (ta.totalamount * (i.amt/100))
END) ) amountafterdiscount
FROM discount i
INNER JOIN cte_calctotalamount ta
ON ta.order_id=i.order_id
UNION
SELECT d.order_id,
d.seq,
d.amt,
ad.totalamount,
CASE
WHEN d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.amountafterdiscount - (d.amt/100))
END totaldiscountedamount,
(amountafterdiscount - (
CASE
WHEN d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.amountafterdiscount - (d.amt/100))
END) ) amountafterdiscount
FROM discount d
INNER JOIN cte_totaldiscountamount ad
ON d.order_id=ad.order_id
AND d.seq=ad.seq+1 )
SELECT *
FROM cte_totaldiscountamount;
请帮助实现以下输出,
order_id totalAmount totalDiscountedAmount amountAfterDiscount
1 200 40 160
您需要在查询中修改 4 项内容
- 在递归查询中,需要初始化第一个结果集。它是下一次迭代的计算基础。在这种情况下,您需要在递归部分的第一个查询中添加
where i.seq = 1
(我们从初始折扣开始)。
- 其次,您没有递归地添加折扣金额。为此,您需要从之前的迭代中检索行折扣金额。所以不是:
case
when d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.AmountAfterDiscount - (d.amt/100))
END totalDiscountedAmount
你应该写:
totalDiscountedAmount + case
when d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.AmountAfterDiscount - (d.amt/100))
END totalDiscountedAmount
您需要在折扣中添加一个新的行增量器。当Union之后的第二次查询的returned结果集为null时,递归查询结束。由于条件 d.seq=ad.seq+1
将为假,查询将 return 为空。这是因为在 discounts
table 中,您的下一个序列是 3 而不是 2。在建议的解决方案中,您可以看到它在折扣的 CTE 中被 returned使用 ROW_NUMBER()
最后,您只需要保留最后一行(因为如果 N 是特定订单的折扣数量,递归查询将 return 自然地 N 行。您可以只需将最后一个输出与示例中所示的子查询连接起来即可。
您的最终查询如下所示:
WITH RECURSIVE CTE_CalcTotalAmount
AS
(
select order_id,sum(amount) As totalAmount from "order"
where order_id=1
group by order_id
),
CTE_DiscountsPerOrder as (
select order_id, seq, amt, type, row_number() over (partition by order_id order by seq asc ) as new_seq from discount ) ,
CTE_TotalDiscountAmount AS
(
select i.order_id,i.new_seq,i.amt,ta.totalAmount as TotalAmount,
case
when i.type='Flat' THEN i.amt
WHEN i.type='Per' THEN (ta.totalAmount * (i.amt/100))
END totalDiscountedAmount,
(totalAmount-
(case
when i.type='Flat' THEN i.amt
WHEN i.type='Per' THEN (ta.totalAmount * (i.amt/100))
END)
) AmountAfterDiscount
from CTE_DiscountsPerOrder i
inner JOIN CTE_CalcTotalAmount ta ON ta.order_id=i.order_id
where i.new_seq=1
UNION
select d.order_id,d.new_seq,d.amt,ad.totalAmount,
totalDiscountedAmount+ case
when d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.AmountAfterDiscount - (d.amt/100))
END totalDiscountedAmount,
(AmountAfterDiscount -
(case
when d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.AmountAfterDiscount - (d.amt/100))
END)
) amountAfterDiscount
From CTE_DiscountsPerOrder d
inner JOIN CTE_TotalDiscountAmount ad on d.order_id=ad.order_id
AND d.new_seq=ad.new_seq+1
)
select * from CTE_TotalDiscountAmount a
join (select order_id, count(*) as totalDiscounts from CTE_DiscountsPerOrder group by 1) b on b.order_id = a.order_id and b.totalDiscounts = a.new_seq;
我有一个场景,我需要汇总 n 个折扣以获得总折扣。每次折扣必须扣除之前的折扣。
例如: 我有一个 200 卢比的订单。 (金额总和)我有多张代金券。第一个让我享受 15% 的折扣,200-(200*(15/100)) = 170。 然后我们有第二张价值 10 卢比的代金券,170-(10) = 160。
顺序很重要,因此还有一个字段记录应用折扣的顺序。
下面是table:
- 订单
id order_id productId amount
1 1 5 160
2 1 9 40
所以没有折扣的总金额是:200 卢比
- 折扣
id order_id seq type amt
1 1 1 Per (%) 15
2 1 3 Flat 10
因此,折扣金额为:((200*(15/100)))
30 + 10 = 40 .
所以我尝试用 CTE 编写 SQL 查询,但它没有给出预期的输出:
WITH recursive cte_calctotalamount AS
(
SELECT order_id,
sum(amount) AS totalamount
FROM ORDER
WHERE order_id=1
GROUP BY order_id ),
cte_totaldiscountamount AS
(
SELECT i.order_id,
i.seq,
i.amt,
ta.totalamount AS totalamount,
CASE
WHEN i.type='Flat' THEN i.amt
WHEN i.type='Per' THEN (ta.totalamount * (i.amt/100))
END totaldiscountedamount,
(totalamount- (
CASE
WHEN i.type='Flat' THEN i.amt
WHEN i.type='Per' THEN (ta.totalamount * (i.amt/100))
END) ) amountafterdiscount
FROM discount i
INNER JOIN cte_calctotalamount ta
ON ta.order_id=i.order_id
UNION
SELECT d.order_id,
d.seq,
d.amt,
ad.totalamount,
CASE
WHEN d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.amountafterdiscount - (d.amt/100))
END totaldiscountedamount,
(amountafterdiscount - (
CASE
WHEN d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.amountafterdiscount - (d.amt/100))
END) ) amountafterdiscount
FROM discount d
INNER JOIN cte_totaldiscountamount ad
ON d.order_id=ad.order_id
AND d.seq=ad.seq+1 )
SELECT *
FROM cte_totaldiscountamount;
请帮助实现以下输出,
order_id totalAmount totalDiscountedAmount amountAfterDiscount
1 200 40 160
您需要在查询中修改 4 项内容
- 在递归查询中,需要初始化第一个结果集。它是下一次迭代的计算基础。在这种情况下,您需要在递归部分的第一个查询中添加
where i.seq = 1
(我们从初始折扣开始)。 - 其次,您没有递归地添加折扣金额。为此,您需要从之前的迭代中检索行折扣金额。所以不是:
case
when d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.AmountAfterDiscount - (d.amt/100))
END totalDiscountedAmount
你应该写:
totalDiscountedAmount + case
when d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.AmountAfterDiscount - (d.amt/100))
END totalDiscountedAmount
您需要在折扣中添加一个新的行增量器。当Union之后的第二次查询的returned结果集为null时,递归查询结束。由于条件
d.seq=ad.seq+1
将为假,查询将 return 为空。这是因为在discounts
table 中,您的下一个序列是 3 而不是 2。在建议的解决方案中,您可以看到它在折扣的 CTE 中被 returned使用ROW_NUMBER()
最后,您只需要保留最后一行(因为如果 N 是特定订单的折扣数量,递归查询将 return 自然地 N 行。您可以只需将最后一个输出与示例中所示的子查询连接起来即可。
您的最终查询如下所示:
WITH RECURSIVE CTE_CalcTotalAmount
AS
(
select order_id,sum(amount) As totalAmount from "order"
where order_id=1
group by order_id
),
CTE_DiscountsPerOrder as (
select order_id, seq, amt, type, row_number() over (partition by order_id order by seq asc ) as new_seq from discount ) ,
CTE_TotalDiscountAmount AS
(
select i.order_id,i.new_seq,i.amt,ta.totalAmount as TotalAmount,
case
when i.type='Flat' THEN i.amt
WHEN i.type='Per' THEN (ta.totalAmount * (i.amt/100))
END totalDiscountedAmount,
(totalAmount-
(case
when i.type='Flat' THEN i.amt
WHEN i.type='Per' THEN (ta.totalAmount * (i.amt/100))
END)
) AmountAfterDiscount
from CTE_DiscountsPerOrder i
inner JOIN CTE_CalcTotalAmount ta ON ta.order_id=i.order_id
where i.new_seq=1
UNION
select d.order_id,d.new_seq,d.amt,ad.totalAmount,
totalDiscountedAmount+ case
when d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.AmountAfterDiscount - (d.amt/100))
END totalDiscountedAmount,
(AmountAfterDiscount -
(case
when d.type='Flat' THEN d.amt
WHEN d.type='Per' THEN (ad.AmountAfterDiscount - (d.amt/100))
END)
) amountAfterDiscount
From CTE_DiscountsPerOrder d
inner JOIN CTE_TotalDiscountAmount ad on d.order_id=ad.order_id
AND d.new_seq=ad.new_seq+1
)
select * from CTE_TotalDiscountAmount a
join (select order_id, count(*) as totalDiscounts from CTE_DiscountsPerOrder group by 1) b on b.order_id = a.order_id and b.totalDiscounts = a.new_seq;