使用PHP识别特定值范围内的行数

时间:2017-05-07 19:23:57

标签: php mysql

我试图弄清楚如何使用PHP确定特定数字范围内的总行数。

我有一个简单的MySQL表,只有一列。该列包含数千行,每行包含0到100之间的数字。

我想出了如何使用array_count_values查找特定数字的行数,但我无法弄清楚如何找到某个范围的行数。

例如,60到80之间有多少个数字?

这是我放在一起查找单个值的代码。我应该添加什么代码来查找范围值?

$query = "SELECT numbers FROM table";
$result = mysqli_query($conn, $query) or die("Error in $query");
$types = array();
while(($row =  mysqli_fetch_assoc($result))) {
    $types[] = $row['numbers'];
}
$counts = array_count_values($types);
echo $counts['12'];

3 个答案:

答案 0 :(得分:2)

如果您需要在多个范围内进行计数,可以使用UNION,这样您就不必发送5个查询。

$query = "SELECT COUNT(numbers) FROM `table` WHERE numbers between 00 and 20
          UNION ALL
          SELECT COUNT(numbers) FROM `table` WHERE numbers between 20 and 40
          UNION ALL
          SELECT COUNT(numbers) FROM `table` WHERE numbers between 40 and 60
          UNION ALL
          SELECT COUNT(numbers) FROM `table` WHERE numbers between 60 and 80
          UNION ALL
          SELECT COUNT(numbers) FROM `table` WHERE numbers between 80 and 100";

答案 1 :(得分:1)

你可以通过以下几种方式做到这一点。

简单方法

SELECT SUM(IF(x BETWEEN 20 AND 30, 1, 0)) AS b_20_30,
       SUM(...) AS b_31_40,
       ...
FROM tableName...

只会在表扫描时返回包含所有结果的一行。

花哨的方式(不是真的推荐

如果您可以提出规则将时间间隔映射到单个数字,例如:

 0...9   => interval i = 0
10...19  => interval i = 1   => the rule is "i = FLOOR(X/10)"
20...29  => interval i = 2

...而且您不需要扫描太多行,您可能会执行不太可维护这样的事情:

SELECT SUM(FLOOR(POW(100, FLOOR(x / 10)))) AS result FROM tableName;

这里,25(20到29之间)的值将变为2,并且总和将增加100 2 。只要你在每组中没有超过100行,最终结果将是单义的权力总和,如果你有 - 比如说 - 在0到9之间的17行,在10到19之间的31行,以及在20之间的74行和29,你会得到一个“神奇的客厅技巧”答案

743117

从那里你可以按顺序恢复行数为74,31,17。

使用1000代替100将产生74031017(并且每组中最多可以处理999个数字)。

请注意,在SELECT中使用函数几乎可以保证您需要完整,慢速的表扫描。

使用速度索引

但我们可以通过明智地使用索引的WHERE来摆脱表扫描并简化生成 - 这在性能方面与UNION相同,但结果更简单,因为它只有一行:

SELECT (SELECT COUNT(*) FROM tableName WHERE x BETWEEN ...) AS b_20_30,
       (...)
; -- no table name on the outer query

这将需要几个子查询(每个间隔一个),但这些子查询将全部使用x上的索引(如果可用),这可以使整个查询非常快。你只需要

 CREATE INDEX x_ndx ON tableName(x);

使用PHP构建查询

假设我们将间隔指定为方便的数组,我们可以使用PHP首先生成查询。无需手动输入所有这些SELECT。

$intervals = [ [ 20, 30 ], [ 17, 25 ], ... ];

function queryFromIntervals(array $intervals) {
    $index = 0;
    return 'SELECT ' . 
        implode(',', array_map(
            function($interval) use ($tableName, &$index) {
                return "(SELECT COUNT(1) FROM {$tableName} WHERE x BETWEEN {$interval[0]} AND {$interval[1]}) AS b_" . ($index++);
            },
            $intervals
        ))
        // . ", (SELECT COUNT(*) FROM {$tableName}) AS total"
        . ';';
    }

这将再次生成一行,其中包含名为b_0b_1的字段,依此类推。它们将包含x的值在$intervals中相应区间的边界之间的行数(区间可能重叠)。

因此,通过执行查询并检索名为$result的元组,您可能会得到

[ 'b_0' => 133, 'b_1' => 29 ]

意味着有133行,x在20到30之间,29有x在17到25之间。您可以在查询中添加最后一个总字段(在上面的代码中注释):

, ... ( SELECT COUNT(*) FROM tableName ) AS total;

也可以获得总行数。

答案 2 :(得分:0)

如果我理解得很好,你会尝试在你的请求中添加一个条件sql。 看看https://www.w3schools.com/sql/sql_where.asp

    $query = "SELECT numbers FROM table WHERE numbers >= 60 AND numbers <= 80";