在一个SQL Server数据集中找到两个本地平均值

时间:2019-05-01 07:55:37

标签: sql sql-server sql-server-2012

在我们公司的工厂中,有一个物理过程,该过程具有两个阶段的开始和两个阶段的完成。当窗口小部件开始进入过程时,将创建一个包含窗口小部件ID和时间戳(DateTimeCreated)的新记录,一旦窗口小部件完全进入该过程,就会在同一记录的不同字段中记录另一个时间戳(DateTimeUpdated)。时间间隔大约是几分钟。

类似地,当窗口小部件开始退出过程时,将创建另一个包含窗口小部件ID和DateTimeCreated的记录,当窗口小部件完全退出过程时,将填充DateTimeUpdated。在当前表设计中,“退出”记录与“输入”记录是无法区分的(尽管给定的窗口小部件ID仅出现一次或两次,因此View可以利用这一事实来进行区分,但现在暂时忽略它)。

窗口小部件的整个处理过程需要几天的时间,但这对讨论并不重要。重要的是,退出流程时的时间间隔总是比进入时长。因此,一组非常简化的,虚构的排序间隔值可能看起来像这样:

  

1、2、2、3、3、3、3、3、3、3、3、4、6、7、7、7、7、8、8、8、8、10、10、10

您可以看到3分钟标记附近的间隔出现一个峰值(“输入”),而7/8分钟标记附近的间隔出现一个峰值(“出口”)。我还排除了5分钟的间隔,以证明进入间隔和退出间隔可以视为互斥的。

我们希望通过使用查询来确定进入和退出数据点集群的本地平均值,来每天监控流程中每个阶段的性能。因此,从概念上讲,两个数据集可以在总体平均值的任一侧进行拆分(在本例中为5.375),然后为拆分以下的值(2.75)和拆分上方的另一个平均值(8)计算平均值。使用上面的数据(随机分布),平均值在下面的图表中以虚线表示。

Interval Chart

我当前的方法是使用两个Common Table Expressions,然后使用最后的三表联接查询。看起来还可以,但我忍不住感觉会更好。有人愿意提供替代方法或其他意见吗?

Table Structure

WITH cte_Raw AS
     (
            SELECT
                   DATEDIFF(minute, DateTimeCreated, DateTimeUpdated) AS [Interval]
            FROM
                   MyTable
            WHERE
                   DateTimeCreated > CAST(CAST(GETDATE() AS date) AS datetime)  -- Today
     )
   , cte_Midpoint AS
     (
            SELECT
                   AVG(Interval) AS Interval
            FROM
                   cte_Raw
     )
SELECT
           AVG([Entry].Interval) AS AverageEntryInterval
         , AVG([Exit].Interval)  AS AverageExitInterval
FROM
           cte_Raw AS [Entry]
           INNER JOIN
                      cte_Midpoint
                      ON
                                 [Entry].Interval < cte_Midpoint.Interval
           INNER JOIN
                      cte_Raw AS [Exit]
                      ON
                                 [Exit].Interval > cte_Midpoint.Interval

2 个答案:

答案 0 :(得分:1)

我认为您的查询不会产生准确的结果。您的两个let ordered = workoutData.sorted { string1, string2 in guard let date1 = formatter.date(from: string1), let date2 = formatter.date(from: string2) else { return false } return date1 < date2 } 正在产生大量的行,从而使平均值下降。它们可能看起来正确(因为其中一个小于另一个),但是您确实进行了计数,因此您会发现查询中的计数与样本数据无关。

如果您只是寻找小于总体平均值且大于总体平均值的平均值,那么您可以使用窗口功能:

JOIN

答案 1 :(得分:0)

我决定发布自己的答案,因为在撰写本文时,两个提议的答案都将无法运行。但是,我删除了JOIN语句,并使用了Gordon提出的CASE语句方法。

我还将DATEDIFF结果乘以1.0,以防止对AVG函数的结果进行舍入。

WITH cte_Raw AS
     (
            SELECT
                   1.0 * DATEDIFF(minute, DateTimeCreated, DateTimeUpdated) AS [Interval]
            FROM
                   MyTable
            WHERE
                   DateTimeCreated > CAST(CAST(GETDATE() AS date) AS datetime)  -- Today
     )
   , cte_Midpoint AS
     (
            SELECT
                   AVG(Interval) AS Interval
            FROM
                   cte_Raw
     )
SELECT AVG(CASE WHEN cte_Raw.Interval < cte_Midpoint.Interval THEN cte_Raw.[Interval] END) AS AverageEntryInterval,
       AVG(CASE WHEN cte_Raw.Interval > cte_Midpoint.Interval THEN cte_Raw.[Interval] END) AS AverageExitInterval
FROM cte_Raw CROSS JOIN cte_Midpoint

此解决方案无法满足弗拉基米尔(Vladimir)表示出场与出场间隔离散不均匀的理论陷阱,因为在实践中我们可以确信不会发生这种情况。