Запрос, который считает различные комбинации - PullRequest
6 голосов
/ 01 августа 2011

Прежде всего, мои извинения за название этого вопроса, у меня нет лучшей идеи на данный момент. Сделайте хорошее предложение, и я исправлю название. (Если у меня есть разрешение на это, я действительно не знаю.)

Ситуация:

Мне трудно выполнить правильный SQL-запрос. У меня есть установка, где люди могут размещать заказы, продукты и т. Д., И при определенных обстоятельствах получают скидки.

Рассмотрим следующую схему:

Product:
  [...]

Price:
  product_id: integer
  description: string
  [...]

Order:
  [...]

OrderItem:
  order_id: integer
  price_id: integer
  amount: integer

И рассмотрим следующие правила:

  • Товаров: 9.
  • Все товары имеют 2 цены, одна с описанием Цена A и одна с описанием Цена B .
  • Все эти цены одинаковы для каждого продукта. (То есть все цены PriceA одинаковы, а все цены PriceB одинаковы.)

Проблема:

Для каждого набора из 5 различных продуктов с одинаковым уровнем цены (т. Е. PriceA против PriceB) общая стоимость заказа снижается на определенную сумму. Я пытаюсь написать запрос, который говорит мне, сколько раз это происходит.

Примеры:

Пример 1:
Пользователь размещает заказ:

  • 5 раз product1,
  • 5 раз product2,
  • 5 раз product3,
  • 3 раза product4,
  • 3 раза product5.

Все на PriceA, клиент получает 3 раза скидку, так как есть 3 комплекта по 5

Пример 2: Пользователь размещает заказ:

  • 5 раз product1,
  • 5 раз product2,
  • 5 раз product3,
  • 5 раз product4,
  • 2 раза product5,
  • 2 раза product6,
  • 2 раза product7

Все цены. Теперь клиент получает 5-кратную скидку, поскольку существует 4 набора по 5, два из которых связаны с продуктом 5, два - с продуктом 6, а другой - с продуктом7.

Борьба:

Я пробовал этот SQL:

SELECT min(amount) as amount from
    (SELECT oi.amount from `order` o
        inner join orderitem oi on oi.order_id = o.id
        inner join price p on oi.price_id = p.id AND p.description = "PriceA"
        inner join product pr on p.product_id = pr.id
        order by oi.amount desc
        limit 5) as z
    having count(amount) = 5;

Это прекрасно работает для примера 1, но в примере 2 он даст неправильный результат, так как выберет первый набор из 5 элементов, а затем проигнорирует

Вопрос в том: это разрешимо в SQL? Или мне лучше расширить выбор и заняться математикой с помощью сценариев? (Мое веб-приложение написано на PHP, поэтому у меня есть место для серверной математики.)

Решение:

Я реализовал решение Нейла; теперь это выглядит так:

/** @var $oid integer The order ID. */

/* Select all amounts ordered per item, only for a given price title. */
$sql = <<<SQL
SELECT oi.amount as amount FROM orderitems oi
    INNER JOIN orders   o  ON oi.order_id  = o.id AND o.id = $oid
    INNER JOIN prices   p  ON oi.price_id  = p.id AND p.title = '%s'
    INNER JOIN products pr ON p.product_id = pr.id
    ORDER BY oi.amount DESC
SQL;
$discountInfo = array(
    array(
        'price'     => 'PriceA',
        'discounts' => array(
            9 => 49.50, /* Key is 'size of set', value is 'discount'. */
            5 => 23.50
        ),
    ),
    array(
        'price' => 'PriceB',
        'discounts'  => array(
            9 => 22,
            5 => 10,
        ),
    ),
);

foreach($discountInfo as $info)
{
    /* Store all ordered amounts per item in Array. */
    $arr = array();
    $result = $this->dbQuery(sprintf($sql,$info['price']));
    while ($row = mysql_fetch_assoc($result)) $arr[] = $row['amount'];

    foreach ($info['discounts'] as $am => $di)
    {
        /* For each highest set of $am items, fetch the smallest member. */
        while (count($arr) >= $am)
        {
            /* Add discount for each complete set */
            $discount += $di * $arr[$am - 1];

            /* Substract the amounts from all members of the set */
            for ($i=0; $i<=$am - 1; $i++) $arr[$i] -= $arr[$am - 1];

            /* Remove all elements that are 0 */
            foreach ($arr as $k=>$v) if ($v == 0) unset ($arr[$k]);

            /* Array is messed up now, re-sort and re-index it. */
            rsort($arr);
        } 
    } 
}

Ответы [ 2 ]

1 голос
/ 01 августа 2011

Вот как я бы сделал это в коде: разделить элементы на два массива, по одному для каждого уровня цен.Для каждого массива товаров, хотя в массиве есть как минимум пять товаров:

  1. Сортировка массива в порядке убывания по количеству товаров
  2. Добавление количества товаровпятого товара в массиве на общее количество скидок
  3. Вычтите количество элементов пятого товара в массиве из первых пяти товаров в массиве
  4. Удалите все нулевые элементы измассив
0 голосов
/ 01 августа 2011

Если я правильно интерпретирую это, вы хотите разделить количество записей на 5 и найти самое низкое целое число (http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_floor)....

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...