【问题标题】:Changing a Query with a numbered result set (with gaps,) to return result with no gaps, containing every number.更改带有编号结果集(带间隙)的查询以返回没有间隙的结果,包含每个数字。
【发布时间】:2012-06-23 21:27:03
【问题描述】:

我有一个选择语句:select a, b, [...];,它返回结果:

a|b
---------
1|8688798
2|355744
4|457437
7|27834

我希望它返回:

a|b
---------
1|8688798
2|355744
3|0
4|457437
5|0
6|0
7|27834

一个不符合我要求的示例查询,因为它没有间隔号:

select
    sub.num_of_ratings,
    count(sub.rater)
from
(
    select 
        r.rater_id as rater,
        count(r.id) as num_of_ratings
    from ratings r
    group by rater
) as sub
group by num_of_ratings;

查询说明: 如果用户对另一个用户进行评分,则评分将列在 rating 表中,评分用户的 id 保存在字段 rater_id 中。实际上,我检查了评分中提到的所有用户,并计算了我为该用户找到了多少评分记录,即rater / num_of_ratings,然后我使用此结果来查找有多少用户对给定次数进行了评分。

最后我知道有多少用户评价了一次,有多少用户评价了两次,等等。我的问题是 count(sub.rater) 的数字从 1、2、3、4、5 开始很好...但是,对于更大的数字,存在差距。这是因为可能有一位用户评分 1028 次,但没有用户评分 1027 次。

我不想应用存储过程循环遍历结果或类似的东西。是否可以在不使用存储过程、循环或创建临时表的情况下填补结果中的这些空白?

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    如果您有一个数字序列,那么您可以对该表执行 JOIN 并正确填充空白。

    您可以查看有关如何获取序列的问题: generate an integer sequence in MySQL

    这是发布的答案之一,可能很容易使用生成从 1 到 10,000 的数字的限制:

    SELECT @row := @row + 1 as row FROM 
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t2, 
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t3, 
    (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, 
    (SELECT @row:=0) t5
    

    【讨论】:

    • 一个解释就好了——t - t4 每一个包含 10 行 dummy 数据,这些的笛卡尔积是 10^4,即 10000 行 dummy 数据,而外部 select 只是 mysql 版本行号
    【解决方案2】:

    使用数字序列,您可以加入您的结果集。例如,假设您的号码列表位于名为 numbersList 的表中,列号为:

    Select number, Count 
    from
      numbersList left outer join
      (select
          sub.num_of_ratings,
          count(sub.rater) as Count
      from
      (
          select 
              r.rater_id as rater,
              count(r.id) as num_of_ratings
          from ratings r
          group by rater
      ) as sub
      group by num_of_ratings) as num
    
    on num.num_of_ratings=numbersList.number
    where numbersList.number<max(num.num_of_ratings) 
    

    显然,您的数字列表必须大于最大值,并且限制将允许它不会将所有数字都设置为最大值。 (如果 MySQL 不允许这种类型的 where 子句,您可以不使用 where 子句以列出最大的所有数字,或者以各种方式修改查询以获得相同的结果。)

    【讨论】:

      【解决方案3】:

      @mazzucci:这个查询太神奇了,你实际上并没有解释这个查询。

      @David:我无法为此目的创建表格(如问题所述)

      基本上我需要的是一个返回无间隙数字列表的选择。然后我可以在该结果集上离开连接并将 NULL 视为 0。

      我需要的是一个任意表,它保存的记录多于最终列表的长度。在以下示例中,我使用表用户:

      select @row := @row + 1 as index
          from (select @row := -1) r, users u
      limit 101;
      

      此查询返回一组从 0 到 100 的数字。将其用作左连接中的子查询最终填补了空白。

      users 只是保持关系引擎运行并因此逐步生成数字的假人。

      select t1.index as a, ifnull(t2.b, 0) as b
      from (
          select @row := @row + 1 as index
              from (select @row := 0) r, users u
          limit 7
      ) as t1
      left join (
          select a, b [...]
      ) as t2
      on t1.index = t2.a;
      

      我没有在现场尝试过这个查询,所以如果有一点瑕疵,请多多支持。但从技术上讲,它是有效的。你明白我的意思。

      编辑:

      只是使用这个概念来获得一个无缝的日期列表,以便在其上留下连接度量:

      select @date := date_add(@date, interval 1 day) as date
          from (select @date := '2010-10-14') d, users u
      limit 700
      

      从 2010/10/15 开始,再迭代 699 天。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-26
        • 1970-01-01
        • 2015-06-26
        相关资源
        最近更新 更多