如果您的产品列表满足以下假设,则有一个解决方案:
您的产品价格在 0.00 到 500.00 之间。例如。 0.01、0.02 等至 499.99。或者可能是 0.05、0.10 等到 499.95。
该算法基于以下内容:
在 n 个总和为 S 的正数的集合中,至少有一个小于 S 除以 n (S/n)
在这种情况下,步骤是:
- 随机选择价格
- 随机选择价格
- 随机选择价格
重复 29 次,得到 29 个产品。对于最后一种产品,选择 价格 = 剩余价格。 (或价格
对于表格项:
获取随机产品最高价格:
CREATE PROCEDURE getRandomProduct (IN maxPrice INT, OUT productId INT, productPrice DECIMAL(8,2))
BEGIN
DECLARE productId INT;
SET productId = 0;
SELECT id, price INTO productId, productPrice
FROM items
WHERE price < maxPrice
ORDER BY RAND()
LIMIT 1;
END
随机获得 29 件商品:
CREATE PROCEDURE get29products(OUT str, OUT remainingPrice DECIMAL(8,2))
BEGIN
DECLARE x INT;
DECLARE id INT;
DECLARE price DECIMAL(8,2);
SET x = 30;
SET str = '';
SET remainingPrice = 500.00;
REPEAT
CALL getRandomProduct(remainingPrice/x, @id, @price);
SET str = CONCAT(str,',', @id);
SET x = x - 1;
SET remainingPrice = remainingPrice - @price;
UNTIL x <= 1
END REPEAT;
END
调用过程:
CALL `get29products`(@p0, @p1); SELECT @p0 AS `str`, @p1 AS `remainingPrice`;
最后尝试找到最后一个达到 500 的产品。
或者,您可以选择 28 并使用您提供的链接问题的解决方案来获得总和为剩余价格的几个产品。
请注意,重复产品是允许的。为避免重复,您可以扩展 getRandomProduct,为已找到的产品添加一个额外的 IN 参数,并添加条件 NOT IN 以排除它们。
更新:您可以克服上述限制,这样您就总能找到总和为 500 的集合,方法是使用所述的 cron 进程在下面的第 2 部分。
第二部分:使用 cron 进程
根据@Michael Zukowski 的建议,您可以
- 创建一个表来保存找到的集合
- 定义一个运行上述算法多次(例如 10 次)的 cron 进程,例如。每 5 分钟一次
- 如果找到与总和匹配的集合,则将其添加到新表中
通过这种方式,您可以找到总和恰好为 500 的集合。当用户提出请求时,您可以从新表中随机选择一个集合。
即使匹配率为 20%,在 24 小时内每 5 分钟运行 10 次算法的 cron 进程也可以收集超过 500 个。
在我看来,使用 cron 进程有以下优点和缺点:
优势
- 查找完全匹配项
- 没有处理客户端请求
- 即使匹配率很低,您也可以找到多个合集
缺点
- 如果价格数据经常更新,您可能会得到不一致的结果,可能使用 cron 进程是行不通的。
- 必须丢弃或过滤旧集合
- 每个客户端可能不是随机的,因为不同的客户端可能会看到相同的集合。