我有一张有价格的商店用品表。我试图编写一个mysql查询,该查询可以随意提取多个项(3到6项),并在用户选择的值的20美元内列出所有项的总价值。
你知道怎么做到这点吗?提前感谢!
编辑*到目前为止,这是我所拥有的。最大的问题是,总金额(价格)占所有项目的总和。第二个问题是“限制”是随机的,但是在运行查询之前,我最终可以让php选择3到6之间的随机数。
SELECT item,price,sum(price)
FROM items
WHERE sum(price) BETWEEN ($value-10) AND ($value+10)
ORDER BY rand() LIMIT 6
发布于 2014-10-28 06:04:12
在SQL查询中,我想不出一种很好的方法,如果不多次将items表加入到表中,这将导致组合爆炸,因为表中的条目数量会增加。
我已经在PHP中找到了一个解决方案,它可以将您的商品分解为价格组。考虑下表:
+----+--------------------+-------+
| id | item | price |
+----+--------------------+-------+
| 1 | apple | 10.5 |
| 2 | banana | 1.85 |
| 3 | carrot | 16.22 |
| 4 | donut | 13.33 |
| 5 | eclair | 18.85 |
| 6 | froyo | 26.99 |
| 7 | gingerbread | 12.15 |
| 8 | honecomb | 50.68 |
| 9 | ice-cream-sandwich | 2.44 |
| 10 | jellybean | 2.45 |
| 11 | kitkat | 2.46 |
| 12 | lollipop | 42.42 |
+----+--------------------+-------+
http://sqlfiddle.com/#!9/0d815
首先,根据项目的随机数量将项目分解为价格组(在您的情况下,在3到6之间)。价格组增加额将由价格差异($20.00)除以所选项目的数量来确定。这确保了您不会超出您的差异。下面是一个由4项组成的组的示例:
PRICE_GROUP_INCREMENT =方差/ NUMBER_ITEMS
PRICE_GROUP_INCREMENT = 20 /4=5
SELECT Count(`id`) AS `item_count`,
Round(`price` / 5) `price_group`
FROM `items`
WHERE `price` <= 35
GROUP BY `price_group`
ORDER BY `price_group` ASC;
结果集:
+------------+-------------+
| item_count | price_group |
+------------+-------------+
| 4 | 0 |
| 2 | 2 |
| 2 | 3 |
| 1 | 4 |
+------------+-------------+
接下来,我们可以搜索结果集,以找到与目标价格组相等的价格组的组合。目标价组由目标价除以价格组增量决定。使用上面的示例,让我们尝试找到4个项目,它们加起来为$35.00,差异为$20.00。
TARGET_PRICE_GROUP =圆形(TARGET_PRICE/ PRICE_GROUP_INCREMENT)
TARGET_PRICE_GROUP =圆形(35.00美元/5.00美元)=7
通过搜索结果集,我们可以得到一个7的目标价组,其中包括4项:
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 0 ORDER BY rand() ASC LIMIT 2;
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 4 ORDER BY rand() ASC LIMIT 1;
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 3 ORDER BY rand() ASC LIMIT 1;
or
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 0 ORDER BY rand() ASC LIMIT 1;
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 3 ORDER BY rand() ASC LIMIT 1;
SELECT `items`.* FROM `items` WHERE ROUND(`price`/5) = 2 ORDER BY rand() ASC LIMIT 2;
为了加快查找一个随机的、合适的查询组合,我编写了一个递归函数,它根据每个价格组中的商品数量随机加权,然后对其进行排序。这加快了速度,因为函数一找到第一个解决方案就会返回。下面是完整的PHP脚本:
<?php
function rand_weighted($weight, $total){
return (float)mt_rand()*(float)$weight/((float)mt_getrandmax()*(float)$total);
};
//you can change these
$targetPrice = 35.00;
$numProducts = rand(3,6);
$maxVariance = 20.00;
$priceGroupIncrement = $maxVariance / $numProducts;
$targetPriceGroupSum = (int)round($targetPrice/$priceGroupIncrement, 0);
$select = "SELECT COUNT(`id`) AS `item_count`, ROUND(`price`/{$priceGroupIncrement}) `price_group`";
$from = "FROM `items`";
$where = "WHERE `price` <= {$targetPrice}";
$groupBy = "GROUP BY `price_group`";
$orderBy = "ORDER BY `price_group` ASC"; //for readability of result set, not necessary
$sql = "{$select} {$from} {$where} {$groupBy} {$orderBy}";
echo "SQL for price groups:\n{$sql};\n\n";
//run your query here and get the result set
//here is a sample result set
//this assumes $targetPrice = 35.00, $numProducts=4, and $maxVariance=20.00
$numProducts = 4;
$priceGroupIncrement = 5;
$targetPriceGroupSum = 7;
$resultSet = array(
array('item_count'=>4, 'price_group'=>0),
array('item_count'=>2, 'price_group'=>2),
array('item_count'=>2, 'price_group'=>3),
array('item_count'=>1, 'price_group'=>4),
);
//end sample result set
$priceGroupItemCount = array();
$priceGroupWeight = array();
$total = 0;
//randomly weight price group based on how many items are in the group
foreach ($resultSet as $result){
$priceGroupItemCount[$result['price_group']] = $result['item_count'];
$total += $result['item_count'];
}
foreach ($resultSet as $result){
$priceGroupWeight[$result['price_group']] = rand_weighted($result['item_count'], $total);
}
//recursive anonymous function to find a match
$recurse = function($priceGroupWeight, $selection=array(), $priceGroupSum=0) use ($priceGroupItemCount, $total, $numProducts, $targetPriceGroupSum, &$recurse){
//sort by random weighted value
arsort($priceGroupWeight);
//iterate through each item in the $priceGroupWeight associative array
foreach ($priceGroupWeight as $priceGroup => $weight){
//copy variables so we can try a price group
$priceGroupWeightCopy = $priceGroupWeight;
$selectionCopy = $selection;
$priceGroupSumCopy = $priceGroupSum + $priceGroup;
//try to find a combination that adds up to the target price group
if (isset($selectionCopy[$priceGroup])){
$selectionCopy[$priceGroup]++;
} else {
$selectionCopy[$priceGroup] = 1;
}
$selectionCount = array_sum($selectionCopy);
if ($priceGroupSumCopy == $targetPriceGroupSum && $selectionCount == $numProducts) {
//we found a working solution!
return $selectionCopy;
} else if ($priceGroupSumCopy < $targetPriceGroupSum && $selectionCount < $numProducts) {
//remove the item from the price group
unset($priceGroupWeightCopy[$priceGroup]);
//if there is still remaining items in the group, add the adjusted weight back into the price group
$remainingInPriceGroup = $priceGroupItemCount[$priceGroup] - $selectionCopy[$priceGroup];
if ($remainingInPriceGroup > 0){
$remainingTotal = $total - count($selection);
$priceGroupWeightCopy[$priceGroup] = rand_weighted($remainingInPriceGroup, $remainingTotal);
}
//try to find the solution by recursing
$tryRecursion = $recurse($priceGroupWeightCopy, $selectionCopy, $priceGroupSumCopy);
if ($tryRecursion !== null){
return $tryRecursion;
}
}
}
return null;
};
$selection = $recurse($priceGroupWeight);
if ($selection===null){
echo "there are no possible solutions\n";
} else {
echo "SQL for items:\n";
foreach ($selection as $priceGroup => $numberFromPriceGroup){
$select = "SELECT `items`.*";
$from = "FROM `items`";
$where = "WHERE ROUND(`price`/{$priceGroupIncrement}) = {$priceGroup}";
$orderBy = "ORDER BY rand() ASC";
$limit = "LIMIT {$numberFromPriceGroup}";
$sql = "{$select} {$from} {$where} {$orderBy} {$limit}";
echo "$sql;\n";
}
}
这种算法方法应该比纯基于SQL查询的解决方案执行得好得多,尤其是在项表增长之后。
发布于 2014-10-22 12:22:17
你需要用“拥有”条款-
SELECT item, price, sum(price) as total_price
FROM items
GROUP BY item
HAVING total_price BETWEEN ($value-10) AND ($value+10)
ORDER BY rand() LIMIT 6
这是一个example,这里是另一个example
在这种情况下,和总是每个项目的总和(使用组BY),如果您只有每一项中的一项,这是很棒的。如果您有一个以上的每一个,和将所有这些项目之和在组中的总和。根据您最初的描述,这是您要寻找的第二个查询,客户在哪里可以看到价格范围内的随机产品。
最好是提供一个表模式(可能使用SQL ),然后向我们展示您希望得到的结果。
https://stackoverflow.com/questions/26495380
复制相似问题