查询计算不同的组合

时间:2011-07-31 21:02:58

标签: sql algorithm math

首先,我对这个问题的标题道歉,我暂时没有更好的想法。提出一个很好的建议,我将修复标题。 (如果我有权这样做,我实际上不知道。)

情况:

我很难完成正确的SQL查询。我有一个设置,人们可以下订单,产品等,并在某些情况下获得折扣。

考虑以下架构:

Product:
  [...]

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

Order:
  [...]

OrderItem:
  order_id: integer
  price_id: integer
  amount: integer

并考虑以下规则:

  • 共有9种不同的产品。
  • 所有商品都有2个价格,一个包含描述 PriceA ,另一个描述 PriceB
  • 每种产品的所有这些价格都是相同的。 (也就是说,所有PriceA价格都相同,且所有PriceB价格都相同。)

问题:

对于相同价格水平(即PriceA与PriceB)的每组5个不同产品,订单的总价格会降低一定数量。我正在尝试编写一个查询,告诉我发生了多少次。

示例:

示例1:
用户下订单:

  • 5次product1,
  • 5次product2,
  • 5倍product3,
  • 3次product4,
  • 产品5次。

所有在PriceA,客户获得3倍的折扣,因为有3套完整的5

示例2: 用户下订单:

  • 5次product1,
  • 5次product2,
  • 5倍product3,
  • 5次product4,
  • 2次product5,
  • 2次product6,
  • 2次product7

所有PriceA价格。现在,客户获得5倍的折扣,因为有4套5个,2个涉及product5,2个涉及product6,1个涉及product7。

斗争:

我试过这个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中解决吗?或者我会更好地扩大我的选择并通过脚本进行数学运算? (我的Web应用程序是用PHP编写的,所以我确实有一些服务器端数学的空间。)

解决方案:

我实施了Neil的解决方案;它现在看起来像这样:

/** @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 个答案:

答案 0 :(得分:1)

我会在代码中执行此操作:将项目拆分为两个数组,每个价格级别一个。对于每个产品阵列,阵列中至少有五个产品:

  1. 按产品项目数
  2. 按降序对数组进行排序
  3. 将数组中第五个产品的项目数添加到折扣总数
  4. 从数组
  5. 中的前五个产品中减去数组中第五个产品的项目数
  6. 删除数组中的所有零元素

答案 1 :(得分:0)

如果我正确地解释了这一点,你想要除以记录的数量除以5,并找到最小的整数(http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions。 HTML#function_floor)......