给出表格摘录:
id | name | age
我正在尝试构建一个将在特定年龄范围内返回10个人的查询。但是,如果该范围内没有足够的人,我想扩大范围,直到找到10个人。
例如,如果我在30-40范围内只找到5个人,我会在25-45范围内找到5个人。
此外,我希望查询能够使用RAND()或类似的顺序,以便每次都能得到不同的结果。
这超出了MySQL可以处理的范围吗?我是否必须将一些逻辑放在应用程序中?
答案 0 :(得分:2)
为效果更新
我的原始解决方案有效,但需要进行表格扫描。我的解决方案是一个很好的解决方案,并且不需要表扫描,但是当唯一匹配远远超出异常值时,其硬编码范围将不起作用。此外,它还需要重复删除记录。但是,如果您有年龄指数,那么结合使用这两种解决方案可以让您获得两全其美的效果。 (如果您没有年龄索引,那么所有解决方案都需要进行表扫描)。
组合解决方案首先只选择可能符合条件的行(所需范围,加上该行范围内的10行和10行),然后使用原始逻辑对结果进行排名。警告:我没有足够的样本数据来验证MySQL的优化器确实足够智能以避免在这里进行表扫描--MySQL可能不够聪明,无法在没有扫描的情况下将这三个UNION编织在一起。
[刚刚更新,修复了2个令人尴尬的SQL错误:DESC应该没有DESC!]
SELECT * FROM
(
SELECT id, name, age,
CASE WHEN age BETWEEN 25 and 35 THEN RAND() ELSE ABS (age-30) END as distance
FROM
(
SELECT * FROM (SELECT * FROM Person WHERE age > 35 ORDER BY age DESC LIMIT 10) u1
UNION
SELECT * FROM (SELECT * FROM Person WHERE age < 25 ORDER BY age LIMIT 10) u2
UNION
SELECT * FROM (SELECT * FROM Person WHERE age BETWEEN 25 and 35) u3
) p2
ORDER BY distance
LIMIT 10
) p ORDER BY RAND() ;
原始解决方案:
我会这样接近:
像这样:
CREATE TABLE Person (id int AUTO_INCREMENT PRIMARY KEY, name varchar(50) NOT NULL, age int NOT NULL);
INSERT INTO Person (name, age) VALUES ("Joe Smith", 26);
INSERT INTO Person (name, age) VALUES ("Frank Johnson", 32);
INSERT INTO Person (name, age) VALUES ("Sue Jones", 24);
INSERT INTO Person (name, age) VALUES ("Ella Frederick", 44);
SELECT * FROM
(
SELECT id, name, age,
CASE WHEN age BETWEEN 25 and 35 THEN RAND() ELSE ABS (age-30) END as distance
FROM Person
ORDER BY distance DESC
LIMIT 10
) p ORDER BY RAND() ;
请注意,我假设,如果范围内没有足够的记录,您想要追加的记录是最接近该范围的记录。如果此假设不正确,请在问题中添加更多详细信息。
re:性能,这需要扫描表格,所以不会很快 - 我现在正在开发一个无扫描解决方案......
答案 1 :(得分:1)
我会做这样的事情:
select * from (
SELECT * FROM (select * from ppl_table where age>30 and age<40 order by rand() limit 10) as Momo1
union
SELECT * FROM (select * from ppl_table where age>25 and age<40 order by rand() limit 20) as Momo2
) as FinalMomo
limit 10
基本上从第一组中选择10个用户,然后从第二组中选择更多用户。 如果第一组不加10,那么第二组将会有更多。
我们从第二组中选择20的原因是因为UNION
将删除重复的值,并且您希望最终结果中至少有10个用户。
修改强>
我从内部as
添加了SELECT
别名,并在内部SELECT
中单独添加,因为MySql不喜欢ORDER BY
UNION
}