【问题标题】:How to limit SQL-result and take avg?如何限制 SQL 结果并取平均值?
【发布时间】:2017-05-20 09:43:01
【问题描述】:

我正在使用此 SQL 查询来选择特定无线传感器节点的所有值,以根据时间戳绘制图表。

SELECT * FROM measurement 
        WHERE nodeId = :nodeId 
        AND datetime BETWEEN :datetimestart 
        AND :datetimeend

查询的数据通过 AJAX 发送给客户端。如果时间戳选择的范围很长,则数组会变大并且数据传输需要很长时间。如果数组限制为 100 个条目会更好。仅将查询限制为 100 并不能解决问题。

我需要做的是选择时间戳的整行并取 100 个不同的内部时间戳的平均值。内部时间戳应该是动态的,并且取决于外部时间戳。

我不知道如何解决这个问题。是否可以根据带有 SQL 查询的时间戳选择 100 个平均数据?还是需要用 PHP 解析数组?

编辑: 表测量结构:

ID          nodeID      humidity    temperature  pressure    voltage     datetime
20519       Node1       46.66       21.39        1013.9      3.313       2017-05-20 10:54:00
20520       Node1       46.87       21.37        1013.9      3.321       2017-05-20 10:54:15
20521       Node1       46.55       21.35        1013.9      3.321       2017-05-20 10:54:30
20522       Node1       46.45       21.35        1013.8      3.321       2017-05-20 10:54:45
20523       Node1       46.68       21.35        1013.9      3.321       2017-05-20 10:55:00
20524       Node1       47.07       21.35        1013.8      3.314       2017-05-20 10:55:15
20525       Node1       47.41       21.36        1013.9      3.321       2017-05-20 10:55:30
20526       Node1       47.51       21.37        1013.9      3.314       2017-05-20 10:55:45
20527       Node1       47.53       21.36        1013.8      3.321       2017-05-20 10:56:00
20528       Node1       46.6        21.33        1013.9      3.321       2017-05-20 10:56:15
20529       Node1       47.14       21.33        1013.9      3.314       2017-05-20 10:56:30
20530       Node1       47.13       21.33        1013.9      3.313       2017-05-20 10:56:46
20531       Node1       48.22       21.36        1013.9      3.321       2017-05-20 10:57:01
20532       Node1       49.96       21.39        1013.9      3.321       2017-05-20 10:57:16
20533       Node1       49.49       21.43        1013.9      3.321       2017-05-20 10:57:31
20534       Node1       49.53       21.49        1014.0      3.321       2017-05-20 10:57:46

EDIT 2我写了一个pythontool来创建sqlite数据库:

    import sqlite3

conn = sqlite3.connect('/var/www/sqliteDatabases/database_sdr.db')                   #connect to database "database.db"
cur = conn.cursor()                                     #create a cursor
cur.execute('PRAGMA foreign_keys = ON')                 #enables the FOREIGN KEY constraint    


#______create table for temperature and humidity with date and time______
cur.execute('''CREATE TABLE measurement(
                ID INTEGER PRIMARY KEY AUTOINCREMENT,
                nodeId text,
                humidity float,
                temperature float,
                pressure float,
                voltage float,
                datetime text)''')
conn.commit()
conn.close()

【问题讨论】:

  • 两者都可以。在查询中执行此操作会使查询更加复杂,并且执行时间会更长。使用 PHP 可以非常有效。这完全取决于您没有告诉我们的数据表的确切结构。我会尝试两者,看看哪个性能和外观最好。
  • 感谢@KIKOSoftware 的快速响应。对我来说,最好通过复杂的 SQL 查询来完成这项任务,而不是用 PHP 解析数组。我的问题是我不知道 SQL 语句应该是什么样子。如果你能给我一个例子,我将非常感激
  • 你能给出表格的结构吗?你现在给出的是表格的内容。这确实暗示了可能的结构,但没有告诉我列的类型等。可以将结构编写为 SQL 查询来创建表。您喜欢复杂的 SQL 查询而不是简单的 PHP 的原因是什么?
  • 好的,我看到 datetime 是 TEXT 类型。我看不到该文本中存储的内容,但您无法像处理日期/时间列一样对文本进行操作。您必须使用 DATETIME 或 TIMESTAMP 类型。请参阅:dev.mysql.com/doc/refman/5.7/en/datetime.html 这将是您的第一步。 (我假设您使用的是 MySQL,对吗?可能是 sqlite3?)
  • 我喜欢 SQL 方式的主要原因是编程风格的清晰性。此外,我正在写关于该应用程序的学士论文,作为一些硬编码的面向对象的 PHP 代码,读者更容易理解 SQL 语句。我正在使用轻量级 SQLite 数据库。在 SQL 中仍然可以使用 datetime 作为文本类型,它只需要采用正确的格式。在我使用的格式中,日期时间的比较没有问题。

标签: php sql arrays limit average


【解决方案1】:

在下面的 SQLite 查询中,我们为每一行计算 period,并使用它对结果进行分组:

SELECT AVG(humidity) AS avgHumidity,
       AVG(temperature) AS avgTemperate,
       AVG(pressure) AS avgPressure,
       AVG(voltage) AS avgVoltage,
       round(100*(julianday(datetime)-julianday(:datetimestart))/
             (julianday(:datetimeend)-julianday(:datetimestart))) AS period   
FROM measurement 
WHERE nodeId = :nodeId AND 
      datetime BETWEEN :datetimestart AND :datetimeend
GROUP BY period

所以基本上你需要对你的结果进行分组。几个注意事项:

  • 我使用了julianday() 函数来实现加法、减法和
    除,这可能不是在 SQLite3 中执行此操作的正确方法。
  • 我多次重复使用:datetimestart:datetimeend。在 MySQL
    这是不允许的。我不知道 SQLite3 中是否允许。如果它 不是简单地将它们重命名为:datetimeend1:datetimeend2 等。
  • 这只是朝着正确方向的未经测试的推动。您需要自己制定细节。

【讨论】:

  • 请注意,我刚刚纠正了周期计算中的一个错误。
  • _ 这非常有帮助,而且还有效!我需要熟悉这个说法。非常感谢
  • 不客气。我很惊讶你让它工作起来,而且速度如此之快。 :-)
  • 我需要将时间段格式化回日期时间。但现在它工作正常,我也在 PHP 中对其进行了编程,现在都可以工作了。如果您想查看图表,请访问底部的 twinzy.hopto.org/test。使用 PHP:$arraysize = count($data); $avgrows = intval($arraysize / 100); for($i = 0; $i < 100; $i++){ $total = 0; for($k = 0; $k<$avgrows; $k++){ $total = $total + $data[$k*$i][$param]; } $datetime[$i] = $data[$k*$i]['datetime']; $avg[$i] = $total/$avgrows; } $data = array( $param => $avg, 'datetime' => $datetime );
  • 链接失效。你测试过哪个更快? SQLite 还是 PHP?在 PHP 中,您可以尝试使用 array_sum() 和一个循环而不是两个嵌套循环。
猜你喜欢
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
  • 2018-06-12
  • 2021-05-03
  • 2020-10-01
  • 1970-01-01
  • 2019-08-28
  • 1970-01-01
相关资源
最近更新 更多