首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >具有多个随机值但和总是在一个范围内的MySQL查询

具有多个随机值但和总是在一个范围内的MySQL查询
EN

Stack Overflow用户
提问于 2014-10-21 20:08:33
回答 2查看 954关注 0票数 1

我有一张有价格的商店用品表。我试图编写一个mysql查询,该查询可以随意提取多个项(3到6项),并在用户选择的值的20美元内列出所有项的总价值。

你知道怎么做到这点吗?提前感谢!

编辑*到目前为止,这是我所拥有的。最大的问题是,总金额(价格)占所有项目的总和。第二个问题是“限制”是随机的,但是在运行查询之前,我最终可以让php选择3到6之间的随机数。

代码语言:javascript
运行
复制
SELECT item,price,sum(price) 
FROM items 
WHERE sum(price) BETWEEN ($value-10) AND ($value+10) 
ORDER BY rand() LIMIT 6
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-10-28 06:04:12

在SQL查询中,我想不出一种很好的方法,如果不多次将items表加入到表中,这将导致组合爆炸,因为表中的条目数量会增加。

我已经在PHP中找到了一个解决方案,它可以将您的商品分解为价格组。考虑下表:

代码语言:javascript
运行
复制
+----+--------------------+-------+
| 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

代码语言:javascript
运行
复制
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; 

结果集:

代码语言:javascript
运行
复制
+------------+-------------+
| 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项:

代码语言:javascript
运行
复制
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脚本:

代码语言:javascript
运行
复制
<?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查询的解决方案执行得好得多,尤其是在项表增长之后。

票数 0
EN

Stack Overflow用户

发布于 2014-10-22 12:22:17

你需要用“拥有”条款-

代码语言:javascript
运行
复制
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 ),然后向我们展示您希望得到的结果。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26495380

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档