Выберите строки из одной таблицы и скорректируйте значения на основе строк в другой таблице - PullRequest
1 голос
/ 30 марта 2020

У меня есть таблица виджетов с идентификатором и соответствующей ценой. У меня также есть таблица скидок. Для одного виджета может быть несколько скидок, каждая из которых представляет собой фиксированную сумму или процентное снижение. Сложные скидки должны применяться в порядке, указанном их положением.

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

Могу ли я создать запрос / процедуру, которая выберет каждый виджет и его окончательную цену после применения всех скидок?

С примерами данных выше:

- 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)

Единственный известный мне способ - присоединить таблицу скидок к таблице виджетов, а затем рассчитать окончательную цену в PHP, как только у меня будут все данные , Однако мои данные - намного более сложная версия этого гипотетического примера. Вероятно, существуют сотни виджетов, многие из которых имеют более чем несколько скидок на отчет, который я пытаюсь сгенерировать.

Образцы данных выше могут быть созданы следующим образом:

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');

1 Ответ

0 голосов
/ 03 апреля 2020

Мы решили решить эту проблему с помощью функции MySQL, которая возвращает скидочную цену виджета по его идентификатору.

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;

Мы можем ВЫБРАТЬ данные следующим образом, чтобы получить каждый виджет со скидкой:

SELECT 
    id,
    price,
    widgetPrice(id) AS discountedPrice
FROM 
widgets;

Что дает нам:

id | price  |  discountedPrice
------------------------------
1  | 10.50  |  7.61
2  | 2.25   |  2.25
3  | 15.75  |  14.17
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...