【问题标题】:Query that counts different combinations计算不同组合的查询
【发布时间】:2011-08-02 00:45:15
【问题描述】:

首先,我很抱歉这个问题的标题,我暂时没有更好的主意。提出一个好的建议,我会修正标题。 (如果我有权这样做,我其实不知道。)

情况:

我很难完成正确的 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:
用户下订单:

  • 乘积1,
  • 乘积2的5倍,
  • 5倍乘积3,
  • 3倍乘积4,
  • 3倍产品5.

全部在PriceA,客户收到3倍的折扣,因为有3套5件

示例 2: 用户下订单:

  • 乘积1,
  • 5 次乘积2,
  • 5 倍产品3,
  • 5倍产品4,
  • 2 倍乘积5,
  • 2 倍乘积6,
  • 2倍乘积7

所有价格一个价格。现在,客户收到 5 倍的折扣,因为有 4 组 5 个,其中两个涉及 product5,两个涉及 product6,一个涉及 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);
        } 
    } 
}

【问题讨论】:

  • 这真的是一道数学题。如果能找到求集合数的算法,写SQL就容易了。
  • @ypercube +1。你是绝对正确的。也许我应该开始在一个更有能力的环境中找到一个解决方案来定义它。不过,在使用 SQL 处理这些事情时,我总是觉得有点手足无措,这可能与我缺乏 SQL 技能有关。
  • 让我看看我是否理解正确。您想按价格对订单中的产品进行分组。 IE。所有具有相同正价和折扣价的产品归为一组。然后,对于每个这样的组,在组内,对于每 5 个产品单位,您要使用折扣价,而不是正常价格。我做对了吗?也就是说,产品 5、6、7 中的产品 x 2、2 和 1 之所以被归为一组,是因为它们的价格相同,是这样吗?
  • @LasseVKarlsen,不!我在使用“折扣”这个词时模棱两可。为了澄清问题,我将“常规”和“折扣”替换为“PriceA”和“PriceB”。减去的折扣是任意数量,始终相同,对我来说,不必在数据库中甚至在查询中。 (它可能只是在脚本中。)在示例 2 中,应该有 5 个集合:1-2-3-4-5 x 2; 1-2-3-4-6×2; 1-2-3-4-7 x 1.

标签: sql algorithm math


【解决方案1】:

这就是我在代码中的做法:将项目分成两个数组,每个数组对应一个价格水平。对于每个产品数组,而数组中至少有五个产品:

  1. 按产品项数降序排列数组
  2. 将数组中第五个产品的商品数量添加到折扣总数中
  3. 从数组的前五个产品中减去数组中第五个产品的项目数
  4. 从数组中删除任何零元素

【讨论】:

  • 我也想到了这一点,我只是觉得把它全部放在 SQL 查询中会很可爱。 (哦,好吧,SQL 中有 WHILE ......这里已经是午夜了,我明天再试一下......)
  • 没有弄湿 MySQL 中的数组之类的东西。我在 PHP 中实现了这个解决方案。请参阅下面的问题。
【解决方案2】:

如果我解释正确,您想将记录数除以 5,然后找到最小整数 (http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions. html#function_floor)....

【讨论】:

  • 不,这并不总是有效。请参阅5,5,5,3,3 他的第一个示例。正确答案:3。你的算法给出了 4。
  • 好点 - 但这是否意味着问题不一致?为什么我们可以将折扣分配给示例 2,而不是示例 3?
  • 不,在示例 3 中,有更多产品 (7) 可供选择(共 5 个)。
  • 想象每种产品都有不同的颜色。如果我理解正确,他想找到具有 5 种不同颜色的 5 种产品的最大组数。
  • @ypercube 是的,5 个不同的产品。 (您可以用 'product.id' 代替 'color'。:))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-30
  • 2023-03-20
  • 2021-01-07
  • 1970-01-01
  • 2016-03-08
  • 1970-01-01
  • 2022-01-25
相关资源
最近更新 更多