[英]Select rows from one table and adjust the values based on rows in another table
I have a table of widgets with an ID and corresponding price.我有一个带有 ID 和相应价格的小部件表。 I also have a table of discounts.
我也有一张折扣表。 There can be multiple discounts per widget, each being either a fixed amount or percentage reduction.
每个小部件可以有多个折扣,每个折扣都是固定金额或百分比减少。 Compound discounts must be applied in the order specified by their position.
复合折扣必须按其位置指定的顺序应用。
widgets
id | price
----------
1 | 10.50
2 | 2.25
3 | 15.75
discounts
id | widgetId | fixedDiscount | percentageDiscount | position
1 | 1 | 0.35 | | 1
2 | 1 | | 25 | 2
3 | 3 | | 10 | 1
Could I create a query/procedure which would select each widget and its final price, after all discounts had been applied?在应用所有折扣后,我可以创建一个查询/程序来选择每个小部件及其最终价格吗?
With the sample data above:使用上面的示例数据:
- Widget 1 should have a 0.35 reduction, then further reduced by 25%. (2 discounts)
- Widget 2 should be unchanged at the original 2.25 (no discount)
- Widget 3 should have a 10% reduction (1 discount)
The only way I am aware of is to join the discounts table to the widgets table and then calculate the final price in PHP once I have all the data.我知道的唯一方法是将折扣表加入小部件表,然后在获得所有数据后用 PHP 计算最终价格。 However, my data is a much more complicated version of this hypothetical example.
但是,我的数据是这个假设示例的复杂得多的版本。 There are likely to be hundreds of widgets with many having more than a handful of discounts for the report I am trying to generate.
可能有数百个小部件,其中许多小部件对我试图生成的报告有很多折扣。
Sample data above can be created like so:可以像这样创建上面的示例数据:
CREATE TABLE `widgets` (
`id` INT NOT NULL AUTO_INCREMENT,
`price` DECIMAL(5,2) NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `discounts` (
`id` INT NOT NULL AUTO_INCREMENT,
`widgetId` INT NOT NULL,
`fixedDiscount` DECIMAL(5,2) NULL,
`percentageDiscount` DECIMAL(4,2) NULL,
`position` TINYINT NOT NULL,
PRIMARY KEY (`id`),
INDEX `fk_widgets_discounts_idx` (`widgetId` ASC),
CONSTRAINT `fk_widgets_discounts`
FOREIGN KEY (`widgetId`)
REFERENCES `widgets` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE);
INSERT INTO
`widgets` (`id`, `price`)
VALUES
('1', '10.50'),
('2', '2.25'),
('3', '15.75');
INSERT INTO
`discounts` (`id`, `widgetId`, `fixedDiscount`, `percentageDiscount`, `position`)
VALUES
('1', '1', '0.35', null , '1'),
('2', '1', null, '25', '2'),
('3', '3', null, '10', '1');
The way we decided to solve this problem was by means of a MySQL function which returns the discounted price of a widget from its id.我们决定解决这个问题的方法是通过一个 MySQL 函数,它从一个小部件的 id 返回一个小部件的折扣价格。
DELIMITER $$
CREATE FUNCTION `widgetPrice`(p_widgetId INT) RETURNS decimal(5,2)
BEGIN
DECLARE v_maxPos INT;
DECLARE v_startPos INT;
DECLARE v_newPrice DECIMAL(5,2);
DECLARE v_fixedDiscount DECIMAL(5,2);
DECLARE v_percentageDiscount DECIMAL(4,2);
DECLARE v_discount DECIMAL (5,2);
SELECT MAX(position) FROM discounts WHERE widgetId = p_widgetId INTO v_maxPos;
SELECT price FROM widgets WHERE id = p_widgetId INTO v_newPrice;
SET v_startPos = 1;
WHILE v_maxPos > 0 DO
SET v_fixedDiscount = 0;
SET v_percentageDiscount = 0;
SET v_discount = 0;
SELECT fixedDiscount, percentageDiscount FROM discounts WHERE widgetId = p_widgetId AND position = v_startPos INTO v_fixedDiscount, v_percentageDiscount;
IF ( v_fixedDiscount IS NOT NULL ) THEN
SET v_discount = v_fixedDiscount;
ELSEIF ( v_percentageDiscount IS NOT NULL ) THEN
SET v_discount = v_newPrice * v_percentageDiscount / 100;
END IF;
SET v_newPrice = v_newPrice - v_discount;
SET v_maxPos = v_maxPos - 1;
SET v_startPos = v_startPos + 1;
END WHILE;
RETURN v_newPrice;
END$$
DELIMITER;
We can SELECT data as follows to retrieve each widget with its discounted price:我们可以按如下方式选择数据来检索每个小部件的折扣价:
SELECT
id,
price,
widgetPrice(id) AS discountedPrice
FROM
widgets;
Which gives us:这给了我们:
id | price | discountedPrice
------------------------------
1 | 10.50 | 7.61
2 | 2.25 | 2.25
3 | 15.75 | 14.17
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.