多次折扣后的产品最终价格
Product Final Price after Many Discount given
我有两个 table。
一 table 个 ID 及其价格,第二个 table 每个 ID 的折扣。
在table的折扣中,一个Id可以有很多折扣,我需要知道一个Id的最终价格。
查询它的最佳方式是什么(在一次查询中)?
对于每个 id 的许多折扣,查询应该是通用的(不仅仅是下面示例中提到的 2 个)
例如
Table一个
id price
1 2.00
2 2.00
3 2.00
Table两个
id Discount
1 0.20
1 0.30
2 0.40
3 0.50
3 0.60
最终结果:
id OrigPrice PriceAfterDiscount
1 2.00 1.12
2 2.00 1.20
3 2.00 0.40
我相信使用 CTE 迭代折扣会产生预期的结果。下面的解决方案可以单独重新运行。
已编辑: 以包含在 CTE 的第一部分中使用左联接的输出中可能没有应用任何折扣的数据。
CREATE TABLE #price
(
id INT,
price DECIMAL(5, 2)
);
CREATE TABLE #discount
(
id INT,
discount DECIMAL(5, 2)
);
INSERT INTO #price
(
id,
price
)
VALUES
(1, 2.00),
(2, 2.00),
(3, 2.00),
(4, 3.50); -- no discount on this item
INSERT INTO #discount
(
id,
discount
)
VALUES
(1, 0.20),
(1, 0.30),
(2, 0.40),
(3, 0.50),
(3, 0.60);
-- new temporary table to add a row number to discounts so we can iterate through them
SELECT d.id,
d.discount,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY d.discount) rn
INTO #GroupedDiscount
FROM #discount AS d;
-- note left join in first part of cte to get prices that aren't discounted included
WITH cte
AS (SELECT p.id,
p.price,
CASE
WHEN gd.discount IS NULL THEN
p.price
ELSE
CAST(p.price * (1.0 - gd.discount) AS DECIMAL(5, 2))
END AS discountedPrice,
gd.rn
FROM #price AS p
LEFT JOIN #GroupedDiscount AS gd
ON gd.id = p.id
AND gd.rn = 1
UNION ALL
SELECT cte.id,
cte.price,
CAST(cte.discountedPrice * (1.0 - gd.discount) AS DECIMAL(5, 2)) AS discountedPrice,
cte.rn + 1 AS rn
FROM cte
INNER JOIN #GroupedDiscount AS gd
ON gd.id = cte.id
AND gd.rn = cte.rn + 1
)
SELECT cte.id,
cte.price,
MIN(cte.discountedPrice) AS discountedPrice
FROM cte
GROUP BY id,
cte.price;
DROP TABLE #price;
DROP TABLE #discount;
DROP TABLE #GroupedDiscount;
结果:
id price discountedPrice
1 2.00 1.12
2 2.00 1.20
3 2.00 0.40
4 3.50 3.50 -- no discount
一般可以通过 LOG/EXP
函数的技巧来完成,但它很复杂。
这是一个基本示例:
declare @p table(id int, price money)
declare @d table(id int, discount money)
insert into @p values
(1, 2),
(2, 2),
(3, 2)
insert into @d values
(1, 0.2),
(1, 0.3),
(2, 0.4),
(3, 0.5),
(3, 0.6)
select p.id,
p.price,
p.price * ca.discount as PriceAfterDiscount
from @p p
cross apply (select EXP(SUM(LOG(1 - discount))) as discount FROM @d where id = p.id) ca
为了更简单(基于游标的方法),您需要递归 CTE
,但在这种情况下,您需要 Discounts
table 到 运行 中的一些唯一排序列它正确。这显示在@Tanner 的回答中。
最后,您可以使用常规 cursor
来解决这个问题
这是另一种方法:
SELECT T1.ID, T1.Price, T1.Price * EXP(SUM(LOG(1 - T2.Discount)))
FROM T1 INNER JOIN T2 ON T1.ID = T2.ID
GROUP BY T1.ID, T1.Price
EXP/LOG 技巧只是另一种做乘法的方法。
如果您在 T1 中有条目而在 T2 中没有折扣,您可以将 INNER JOIN 更改为 LEFT JOIN。你最终会得到以下结果:
ID Price Discount
4 2.00 NULL
您的逻辑可以考虑折扣价列中的空值并取而代之的是原始价格,或者只为那些添加 0 折扣记录。
正如其他人所说,EXP(SUM(LOG()))
是进行计算的方法。从另一个角度来看,这是基本相同的方法:
WITH CTE_Discount AS
(
SELECT Id, EXP(SUM(LOG(1-Discount))) as TotalDiscount
FROM TableTwo
GROUP BY id
)
SELECT t1.id, CAST(Price * COALESCE(TotalDiscount,1) AS Decimal(18,2)) as FinalPRice
FROM TableOne t1
LEFT JOIN CTE_Discount d ON t1.id = d.id
我有两个 table。 一 table 个 ID 及其价格,第二个 table 每个 ID 的折扣。 在table的折扣中,一个Id可以有很多折扣,我需要知道一个Id的最终价格。
查询它的最佳方式是什么(在一次查询中)? 对于每个 id 的许多折扣,查询应该是通用的(不仅仅是下面示例中提到的 2 个)
例如 Table一个
id price
1 2.00
2 2.00
3 2.00
Table两个
id Discount
1 0.20
1 0.30
2 0.40
3 0.50
3 0.60
最终结果:
id OrigPrice PriceAfterDiscount
1 2.00 1.12
2 2.00 1.20
3 2.00 0.40
我相信使用 CTE 迭代折扣会产生预期的结果。下面的解决方案可以单独重新运行。
已编辑: 以包含在 CTE 的第一部分中使用左联接的输出中可能没有应用任何折扣的数据。
CREATE TABLE #price
(
id INT,
price DECIMAL(5, 2)
);
CREATE TABLE #discount
(
id INT,
discount DECIMAL(5, 2)
);
INSERT INTO #price
(
id,
price
)
VALUES
(1, 2.00),
(2, 2.00),
(3, 2.00),
(4, 3.50); -- no discount on this item
INSERT INTO #discount
(
id,
discount
)
VALUES
(1, 0.20),
(1, 0.30),
(2, 0.40),
(3, 0.50),
(3, 0.60);
-- new temporary table to add a row number to discounts so we can iterate through them
SELECT d.id,
d.discount,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY d.discount) rn
INTO #GroupedDiscount
FROM #discount AS d;
-- note left join in first part of cte to get prices that aren't discounted included
WITH cte
AS (SELECT p.id,
p.price,
CASE
WHEN gd.discount IS NULL THEN
p.price
ELSE
CAST(p.price * (1.0 - gd.discount) AS DECIMAL(5, 2))
END AS discountedPrice,
gd.rn
FROM #price AS p
LEFT JOIN #GroupedDiscount AS gd
ON gd.id = p.id
AND gd.rn = 1
UNION ALL
SELECT cte.id,
cte.price,
CAST(cte.discountedPrice * (1.0 - gd.discount) AS DECIMAL(5, 2)) AS discountedPrice,
cte.rn + 1 AS rn
FROM cte
INNER JOIN #GroupedDiscount AS gd
ON gd.id = cte.id
AND gd.rn = cte.rn + 1
)
SELECT cte.id,
cte.price,
MIN(cte.discountedPrice) AS discountedPrice
FROM cte
GROUP BY id,
cte.price;
DROP TABLE #price;
DROP TABLE #discount;
DROP TABLE #GroupedDiscount;
结果:
id price discountedPrice
1 2.00 1.12
2 2.00 1.20
3 2.00 0.40
4 3.50 3.50 -- no discount
一般可以通过 LOG/EXP
函数的技巧来完成,但它很复杂。
这是一个基本示例:
declare @p table(id int, price money)
declare @d table(id int, discount money)
insert into @p values
(1, 2),
(2, 2),
(3, 2)
insert into @d values
(1, 0.2),
(1, 0.3),
(2, 0.4),
(3, 0.5),
(3, 0.6)
select p.id,
p.price,
p.price * ca.discount as PriceAfterDiscount
from @p p
cross apply (select EXP(SUM(LOG(1 - discount))) as discount FROM @d where id = p.id) ca
为了更简单(基于游标的方法),您需要递归 CTE
,但在这种情况下,您需要 Discounts
table 到 运行 中的一些唯一排序列它正确。这显示在@Tanner 的回答中。
最后,您可以使用常规 cursor
来解决这个问题这是另一种方法:
SELECT T1.ID, T1.Price, T1.Price * EXP(SUM(LOG(1 - T2.Discount)))
FROM T1 INNER JOIN T2 ON T1.ID = T2.ID
GROUP BY T1.ID, T1.Price
EXP/LOG 技巧只是另一种做乘法的方法。
如果您在 T1 中有条目而在 T2 中没有折扣,您可以将 INNER JOIN 更改为 LEFT JOIN。你最终会得到以下结果:
ID Price Discount
4 2.00 NULL
您的逻辑可以考虑折扣价列中的空值并取而代之的是原始价格,或者只为那些添加 0 折扣记录。
正如其他人所说,EXP(SUM(LOG()))
是进行计算的方法。从另一个角度来看,这是基本相同的方法:
WITH CTE_Discount AS
(
SELECT Id, EXP(SUM(LOG(1-Discount))) as TotalDiscount
FROM TableTwo
GROUP BY id
)
SELECT t1.id, CAST(Price * COALESCE(TotalDiscount,1) AS Decimal(18,2)) as FinalPRice
FROM TableOne t1
LEFT JOIN CTE_Discount d ON t1.id = d.id