代码之家  ›  专栏  ›  技术社区  ›  webguydan

具有动态范围的MySQL查询?

  •  1
  • webguydan  · 技术社区  · 16 年前

    给定表片段:

    id | name | age
    

    我试图形成一个查询,返回特定年龄范围内的10个人。但是,如果没有足够的人在这个范围内,我想扩大范围,直到我可以找到10人。

    例如,如果我在30-40的范围内只找到5个人,我会在25-45的范围内找到5个人。

    此外,我希望查询能够使用order by RAND()或类似的方法,以便每次都能得到不同的结果。

    这是否超出了MySQL所能处理的范围?我需要在应用程序中加入一些逻辑吗?

    2 回复  |  直到 16 年前
        1
  •  1
  •   Amirshk    16 年前

    我会这样做:

    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

    编辑

    我添加了 as 来自内部的别名 SELECT ,并在内部制作了一个单独的 因为MySql不喜欢 ORDER BY 具有

        2
  •  2
  •   Justin Grant    16 年前

    更新性能:

    我最初的解决方案有效,但需要扫描表。Am的解决方案是一个很好的解决方案,它不需要表扫描,但当唯一的匹配项是远异常值时,它的硬编码范围将不起作用。此外,它还需要对记录进行重复数据消除。但是,如果你有一个关于年龄的指数,结合这两种解决方案可以让你两全其美(如果没有年龄索引,则所有解决方案都需要进行表扫描)。

    [刚刚再次更新以修复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() ;
    

    原始解决方案:

    我会这样做:

    1. 将排序结果集中该距离内的记录数修剪为10条记录

    这样地:

    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:性能,这需要扫描整个表,所以不会很快——我正在开发一个无扫描解决方案。。。