【发布时间】: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.