10

我在下面有一个简单的表 BIRDCOUNT,显示在任何一天计算了多少只鸟:

+----------+
| NUMBIRDS |
+----------+
| 123      |
| 573      |
| 3        |
| 234      |
+----------+

我想创建一个频率分布图,显示多少次鸟类被计算在内。所以我需要 MySQL 来创建类似的东西:

+------------+-------------+
| BIRD_COUNT | TIMES_SEEN  |
+------------+-------------+
| 0-99       | 17          |
| 100-299    | 23          |
| 200-399    | 12          |
| 300-499    | 122         |
| 400-599    | 3           |
+------------+-------------+

如果鸟类数量范围是固定的,这将很容易。但是,我永远不知道看到多少只鸟的最小值/最大值。所以我需要一个选择语句:

  1. 创建与上述类似的输出,始终创建 10 个计数范围。
  2. (更高级)创建类似于上面的输出,总是创建 N 个计数范围。

我不知道#2是否可以在一次选择中进行,但任何人都可以解决#1吗?

4

4 回答 4

8
SELECT
    FLOOR( birds.bird_count / stat.diff ) * stat.diff as range_start, 
    (FLOOR( birds.bird_count / stat.diff ) +1) * stat.diff -1 as range_end, 
    count( birds.bird_count ) as times_seen
FROM birds_table birds, 
    (SELECT 
        ROUND((MAX( bird_count ) - MIN( bird_count ))/10) AS diff
    FROM birds_table
    ) AS stat
GROUP BY FLOOR( birds.bird_count / stat.diff )

在这里,您可以回答您的两个问题;] 不同之处在于范围的开始和结束位于单独的列中,而不是连接在一起,但是如果您需要在一列中使用它,我想您可以从这里开始。要更改范围数,只需编辑数字 10 您可以在子查询中找到。

于 2013-02-24T21:52:52.783 回答
3

当创建这样的东西时,GROUP BY 是你的朋友。基本思想是将每个值放入一个桶中,然后统计每个桶中的元素个数。要创建存储桶,您需要定义一个函数来获取该值并计算存储桶的唯一值。

像这样的东西:

SELECT
  @low := TRUNCATE(bird_count/100, 0) * 100 as Low,
  TRUNCATE(@low + 99, 0) as High,
  COUNT(*) AS Count
FROM birds_seen
GROUP BY Low;

在这种情况下,您定义一个函数来计算鸟类数量,并计算桶的下限。然后,您将下限范围内的所有值分组,例如,这会将 123 和 145 放入标有“100”的存储桶中,将 234 和 246 放入标有“200”的存储桶中。

现在,每个值都放在一个桶中,您可以按桶标签对值进行分组,并计算每个桶中元素的数量。

于 2013-02-24T20:43:23.227 回答
1

我猜你的实际 SQL 查询:

SELECT dateColumn, COUNT(*) AS NUMBIRDS
FROM birdTable
GROUP BY dateColumn

如果是这样,您所要做的就是“分类”您的计数:

SELECT CONCAT_WS('-', 
   FLOOR( NUMBIRDS/100 )*100,
   ((FLOOR( NUMBIRDS/100 )+1)*100) - 1
) AS BIRD_COUNT
,COUNT(*) AS TIMES_SEEN
FROM (
    SELECT dateColumn, COUNT(*) AS NUMBIRDS
    FROM birdTable
    GROUP BY dateColumn
) AS birdCounts
GROUP BY BIRD_COUNT

当然,如果缺少其中一个范围,您将不会获得匹配的行 - 但如果这是一个问题,您可以使用 LEFT JOIN 轻松解决该问题。

于 2013-02-24T20:41:19.597 回答
1

在@gustek答案和维基百科的直方图页面的基础上,这里有几个解决方案,使用斯科特规则和赖斯规则,使用箱数公式动态设置箱宽 h, k = \ceil{ (最大值 - 最小值) / h }

# Histogram generator using Scott's rule, width(h) = (max - min) / k
SELECT any_value(FLOOR(r2.value / stat.width) * stat.width) as range_start,
       count(r2.value)                                      as times_seen,
FROM RESULT r2,
 (
     select 3.49 * stddev(r.value) / (power(count(*), 1 / 3)) as width
     from RESULT r
 ) as stat
GROUP BY FLOOR(r2.value / stat.width);

# Histogram using Rice rule k = ceil(2*n^1/3), width(h) = (max - min) / k
SELECT any_value(FLOOR(r2.value / stat.width) * stat.width) as range_start,
       count(r2.value)                                      as times_seen,
FROM RESULT r2,
 (
     select (max(r.value) - min(r.value)) / ceil(2 * power(count(*), 1 / 3)) as width
     from RESULT r
 ) as stat
GROUP BY FLOOR(r2.value / stat.width);

any_value()函数用于解决新的 MySQLONLY_FULL_GROUP_BY问题。

于 2019-06-21T03:37:15.520 回答