【问题标题】:Identifying the number of rows within a specific value range using PHP使用 PHP 识别特定值范围内的行数
【发布时间】:2017-05-07 19:23:57
【问题描述】:

我试图弄清楚如何使用 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'];

【问题讨论】:

  • 为什么不只计算执行查询的返回数?即:SELECT *** WHERE 介于 60/80 之间?
  • 因为我想要 0 到 20、20 到 40、40 到 60、60 到 80 和 80 到 100 的值。所以,据我所知,我必须进行 5 次查询,而不是1.
  • 你可以使用UNION
  • 嗨,Dan,你能告诉我更多关于 UNION 的信息吗?
  • UNIONUNION ALL 允许您将多个 SELECT 语句链接在一起,只要返回的行数相同。所以你可以为每个范围添加一个语句;例如:SELECT COUNT(numbers) AS c, '0-20' AS r FROM table WHERE numbers BETWEEN 0 AND 20 UNION ALL SELECT COUNT(numbers) AS c, '21-40' AS r FROM table WHERE numbers BETWEEN 21 AND 40 等。

标签: php mysql


【解决方案1】:

如果您需要在多个范围内计数,您可以使用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";

【讨论】:

  • 您需要使用UNION ALL,因为如果多个查询返回相同的计数,则只会返回一个值来表示所有结果。
  • 有趣。谢谢你。我会这样做的。
【解决方案2】:

您可以通过多种方式做到这一点。

简单方式(一次全表扫描)

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,总和将增加 1002。只要每组中的行数不超过 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;

还可以获得总行数。

同样的函数,改变内部的return 值,可以适应生成使用IF而不是SELECT的“简单”查询。

【讨论】:

  • 感谢您花时间写下所有这些建议。目前,其中一些对我来说有点先进,但我会继续努力。 - 谢谢。
【解决方案3】:

为什么不让数据库为您完成繁重的工作?

$query = "SELECT COUNT(*) FROM table WHERE numbers BETWEEN 60 AND 80";
$result = mysqli_query($conn, $query) or die("Error in $query");
$row =  mysqli_fetch_array($result, MYSQLI_NUM);
echo $row[0];

【讨论】:

  • 我认为你的回答是正确的。不过,我试图弄清楚如何在 PHP 中做到这一点。
  • 感谢您的建议-UNION 是我应该做的-谢谢!
【解决方案4】:

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

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

【讨论】:

  • 我接受查询可以完成这项工作,但我怎么能使用 PHP 做到这一点?
  • 可以更清楚,你想保护请求吗?,知道如何连接数据库吗?
  • 我了解如何进行查询。我只是想知道如何使用我描述的查询在 PHP 中完成此操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-19
  • 1970-01-01
  • 1970-01-01
  • 2020-03-11
  • 1970-01-01
  • 2019-10-31
  • 1970-01-01
相关资源
最近更新 更多