【问题标题】:Returning an average value of results返回结果的平均值
【发布时间】:2018-05-10 16:44:56
【问题描述】:

我们有一个系统,该系统每小时可存储来自各种传感器的 1000 条读数。这些值被发送到 .net 图表模块中。它可以工作,但是当您查看几天的数据时,基本上有成千上万的结果被输入到图表中,并且处理它们的速度很慢。作为一个快速修复,我将其设置为将所有结果分组并平均到一个小时桶中,方法是将日期列分解为小时(去掉分钟和秒)。这工作得更快,但我希望它变得更好。这是当前(庞大的)查询:

SELECT Value, CAST(CAST(yr AS char(4)) + '/' + CAST(mth AS char(2)) + '/' + CAST(dte AS char(2)) + ' ' + CAST(hr AS char(2)) + ':00:00' AS datetime) AS Date FROM (SELECT AVG(Value) AS Value, DATEPART(year, Date) AS yr, DATEPART(month, Date) AS mth, DATEPART(day, Date) AS dte, DATEPART(hour, Date) AS hr FROM SensorReadings WHERE (SensorID='15') AND (Date >= DATEADD(hour, - 336, getutcdate())) GROUP BY DATEPART(year, Date), DATEPART(month, Date), DATEPART(day, Date), DATEPART(hour, Date)) AS derivedtbl_1 ORDER BY date

这可以返回几千个结果。让可能只有 300 像素宽的图表模块尝试绘制基本上会重叠的 1000 个点似乎仍然没有效率。

我的问题是:有没有办法告诉 SQL 只返回 300 个结果并让它平均 Value 和 Date 列?粗略地类似于“仅选择 300 avg(value) 作为 Value,ave(date) as Date from SensorReadings order by Date”

谢谢!

【问题讨论】:

  • 您可以使用 TOP docs.microsoft.com/en-us/sql/t-sql/queries/… 选择最近的值。如果您最近的值位于表的底部,您可能需要执行 ORDER BY ID ASC 或 DESC 以获取表顶部的最新数据。遗憾的是,我目前没有安装 MSSQL 来测试它。

标签: sql .net sql-server


【解决方案1】:

有两种技术可以按一定的行数过滤结果。在 Select 语句中只需在开头添加 TOP (300) 即可限制行数。如果要使用数学百分比,则可以使用 TOP (2) PERCENT。或者,可以使用 offset 和 fetch 在结果之间进行过滤。

对于查询构造,是否可以不将派生表用于 from 语句并直接从传感器读数中准备好?您可以只对主要选择语句中的列使用 avg 函数。如果您有来自 sensorreadings 的行样本输出,那将很有帮助。从传感器读数中选择顶部 (5) *。

【讨论】:

    【解决方案2】:

    这将起作用 - 它按读数数量将范围分成偶数段:

    DECLARE @Partitions INT = 300;
    
    WITH AllValues AS
    (  SELECT Value,Date,RowNum = ROW_NUMBER() over(ORDER BY Date asc)
       FROM SensorReadings WHERE (SensorID='15')
    )
    SELECT AverageValue = AVG(Value),
           AverageTime = DATEADD(second,AVG(CAST(datediff(second,'1/1/2000',Date) as BIGINT)),'1/1/2000')
    FROM AllValues
    GROUP BY RowNum / @Partitions
    ORDER BY RowNum / @Partitions
    

    请注意,您不能取日期时间的平均值;但您可以取自给定时间以来的平均秒数。

    【讨论】:

    • 谢谢,这已经足够接近让我指出正确的方向。我将发布我将发布的最终解决方案。
    【解决方案3】:

    感谢上面的 Mark 让我找到了正确的方向。这是我要工作的最后一个 SQL。我首先需要确定总行数以获得正确的次数来划分 Row_Number。这大大提高了网站性能!

    Declare @Partitions int
    select    @Partitions=  count(value)/300 +1
    from SensorReadings
    WHERE     (SensorID = '31') and date>'4/1/2018';
    WITH AllValues as
    (
    SELECT     Value, Date, RowNum = ROW_NUMBER() OVER (ORDER BY Date 
    ASC)/@Partitions
    FROM         SensorReadings
    WHERE     (SensorID = '31') and date>'4/1/2018'
    )
    SELECT AverageValue = AVG(Value),
       AverageTime = DATEADD(second,AVG(CAST(datediff(second,'1/1/2000',Date) as 
    BIGINT)),'1/1/2000')
    FROM AllValues
    GROUP BY RowNum 
    ORDER BY RowNum 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-13
      • 2020-02-29
      • 2022-01-12
      • 2015-10-03
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      相关资源
      最近更新 更多