【问题标题】:Find Average, MaxValue and MinValue and the Corresponding DateTime that the Values occur查找平均值、最大值和最小值以及值出现的对应日期时间
【发布时间】:2020-03-16 15:11:32
【问题描述】:

我正在处理一个 SQL 查询,我必须找出任何日期的每个组的平均值、最大值、最大值-日期时间、最小值、最小值-日期时间。为此,我使用了以下查询

SELECT
    Dl.TagDescID,
    convert( decimal(18,2), AVG( Dl.Value ) ) AS 'TotalAvgValue',
    convert(decimal(18,2), MAX( Dl.Value ) ) AS 'MaxValue',
    MAX( Dl.Date ) MaxDate,
    convert( decimal(18,2), MIN( Dl.Value ) ) AS 'MinValue',
    Min( Dl.Date ) MinDate
FROM
    tblDataLog AS Dl WITH (nolock) 
    INNER JOIN tblTagDescription AS TD WITH (nolock) ON Dl.TagDescID = TD.ID 
WHERE
    ( CONVERT(date, Dl.Date, 103) = CONVERT(date, @StartDate, 103) )
    AND
    ( TD.GroupName = @Group )
GROUP BY
    Dl.TagDescID
`

     TagDescID  TotalAvgValue   MaxValue    MaxDate MinValue    MinDate
       1    36.59   36.59   2020-01-07 10:13:42.293 36.59   2020-01-07 10:13:32.750
       2    20.49   20.49   2020-01-07 10:13:42.293 20.49   2020-01-07 10:13:32.750

In the above Data Set The MaxValue of TagDescID 1 is 36.59 and its Date as 'MaxDate' should be the exact datetime when this maxvalue Arrives in the table tblDataLog. here Max-Date of MaxValue of TagDescID 1 is '2020-01-07 10:13:42.293' but the value should have been '2020-01-07 08:13:42.293'. Same for MinValue and MinDate For each TagDescID.

How to solve it?



【问题讨论】:

  • 您应该包含一个汇总数据集和结果集,以显示您的预期和实际观察到的结果
  • 所以你想通过 Date 过滤,但也返回 Max(Date)Min(Date) 我认为我们在这里遗漏了一些东西,如果我们过滤日期,那么 Max 和 Min 将是相同的值...或者您是否在寻找指定日期的最大和最小时间?
  • 我想要任意日期的每个 TagDescID 的平均值、MaxValue、MaxValue DateTime、MinValue、MinValue DateTime
  • 请提供一些示例数据和预期结果 - 这是清楚地传达您正在寻找的内容的唯一方法。此外,除非绝对必要,否则您当然应该避免使用with (nolock)
  • 您不应该使用CONVERT( date, Dl.Date, 103 ),因为它不是 SARGable 谓词。为什么@StartDate 不是date 值? CREATE TABLE 语句中Dl.Date 的实际数据类型是什么?

标签: sql-server datetime


【解决方案1】:

问题是您实际上是在同时要求多个聚合和分组集。您观察到的是,每个 column 聚合 表达式都独立于其他列返回该聚合的结果,这是设计使然。

在上述查询中MaxDateMinDate 应该是当MaxValueMinValue 插入到表tblDataLog 时的日期时间

在 SQL Server 中,我们有多种查询方法。

一种方法是查询集合中的最大值和最小值,然后重新查询集合中的最大值和最小值日期。

在此示例中,我使用 CTE 而不是简单的嵌套查询,因为我发现语法更具可读性。

两个CROSS APPLY 查询将为Daily CTE 中的每个结果评估一次。 此解决方案可以更有效地对相应日志记录的 DateTime 使用内联查找,因为它不必为 tblDataLog 中的每一行查找一次,此解决方案将导致对每一行进行 2 次额外查找由 group by 返回。

;WITH Daily as
(
    SELECT  
        Dl.TagDescID, 
        convert(decimal(18,2),AVG(Dl.Value)) AS [TotalAvgValue],
        convert(decimal(18,2),MAX(Dl.Value)) AS [MaxValue], 
        convert(decimal(18,2),MIN(Dl.Value)) AS [MinValue] 
    FROM @tblDataLog AS Dl  
    INNER JOIN @tblTagDescription AS TD ON Dl.TagDescID = TD.ID 
    WHERE (CONVERT(date, Dl.Date, 103) = CONVERT(date, @StartDate, 103)) AND (TD.GroupName=@Group) 
    GROUP BY Dl.TagDescID  
)
SELECT Daily.TagDescID, TotalAvgValue, MaxValue, [Max].Date MaxDate, MinValue, [Min].Date MinDate
FROM Daily
CROSS APPLY (SELECT MAX(DlMax.Date) Date FROM @tblDataLog DlMax WHERE DlMax.TagDescID = Daily.TagDescId AND (CONVERT(date, DlMax.Date, 103) = CONVERT(date, @StartDate, 103)) AND DlMax.Value = Daily.MaxValue) as [Max]
CROSS APPLY (SELECT MIN(DlMin.Date) Date FROM @tblDataLog DlMin WHERE DlMin.TagDescID = Daily.TagDescId AND (CONVERT(date, DlMin.Date, 103) = CONVERT(date, @StartDate, 103)) AND DlMin.Value = Daily.MinValue) as [Min]

另一种方法是按日期分组,而不是过滤明确的日期值,因此这将按日期和标签进行汇总,如果需要,可为您提供跨多个日期和多个标签的报告:

;WITH Daily as
(
    SELECT  
        Dl.TagDescID, 
        TD.GroupName,
        CONVERT(date, Dl.Date, 103) as Date,
        MAX(Dl.Date) as Max_Date,
        MIN(Dl.Date) as Min_Date,
        convert(decimal(18,2),AVG(Dl.Value)) AS [TotalAvgValue],
        convert(decimal(18,2),MAX(Dl.Value)) AS [MaxValue], 
        convert(decimal(18,2),MIN(Dl.Value)) AS [MinValue] 
    FROM @tblDataLog AS Dl  
    INNER JOIN @tblTagDescription AS TD ON Dl.TagDescID = TD.ID 
    GROUP BY Dl.TagDescID, TD.GroupName, CONVERT(date, Dl.Date, 103)
)
SELECT Daily.Date, Daily.GroupName, Daily.TagDescID, TotalAvgValue, MaxValue, [Max].Date MaxDate, MinValue, [Min].Date MinDate
FROM Daily
CROSS APPLY (SELECT MAX(DlMax.Date) Date FROM @tblDataLog DlMax WHERE DlMax.TagDescID = Daily.TagDescId AND DlMax.Date >= Daily.Min_Date AND DlMax.Date <= Daily.Max_Date) [Max]
CROSS APPLY (SELECT MIN(DlMin.Date) Date FROM @tblDataLog DlMin WHERE DlMin.TagDescID = Daily.TagDescId AND DlMin.Date >= Daily.Min_Date AND DlMin.Date <= Daily.Max_Date) [Min]
-- Optional Date Filter
-- WHERE TD.GroupName=@Group AND Daily.Date = @StartDate

在我的测试集中,返回:

Date        GroupName   TagDescID   TotalAvgValue   MaxValue    MaxDate                      MinValue   MinDate
2020-03-11  Test        1           5.00            8.00        2020-03-11  22:00:00.000     2.00       2020-03-11 10:00:00.000
2020-03-15  Test        1           5.00            8.00        2020-03-15  13:00:00.000     2.00       2020-03-15 06:00:00.000

取消注释where 子句以启用您的日期过滤器,或者您可以将其更改为一个日期范围,您仍然会看到按天显示的结果。

【讨论】:

    【解决方案2】:

    我想这就是你所追求的。 Value时对应的Date是最小值和最大值。您可以使用sub-query 来执行此操作

    SELECT
        Dl.TagDescID,
        convert( decimal(18,2), AVG( Dl.Value ) ) AS 'TotalAvgValue',
        convert(decimal(18,2), MAX( Dl.Value ) ) AS 'MaxValue',
        --MAX( Dl.Date ) MaxDate,
        (SELECT TOP 1 x.[Date] FROM  tblDataLog x WHERE x.TagDescID = Dl.TagDescID ORDER BY Value DESC) As MaxDate,
        convert( decimal(18,2), MIN( Dl.Value ) ) AS 'MinValue',
        --Min( Dl.Date ) MinDate
        (SELECT TOP 1 x.[Date] FROM  tblDataLog x WHERE x.TagDescID = Dl.TagDescID ORDER BY Value) As MinDate
    FROM
        tblDataLog AS Dl WITH (nolock) 
        INNER JOIN tblTagDescription AS TD WITH (nolock) ON Dl.TagDescID = TD.ID 
    WHERE
        ( CONVERT(date, Dl.Date, 103) = CONVERT(date, @StartDate, 103) )
        AND
        ( TD.GroupName = @Group )
    GROUP BY
        Dl.TagDescID
    

    编辑:正如其他人评论的那样,避免CONVERT(date, Dl.Date, 103) = CONVERT(date, @StartDate, 103)

    您可以将其替换为

    WHERE Dl.Date >= @StartDate
    AND   Dl.Date <  DATEADD (DAY, 1, @StartDate)
    

    【讨论】:

    • 上述查询显示错误的 Max-Date 和 Min-Time。我正在搜索 20 年 1 月 7 日,它显示的是 2020 年 1 月 3 日和 2020 年 1 月 6 日。
    • 如果你能提供一些样本数据那就太好了。截至目前,我们只是在猜测您的要求
    猜你喜欢
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-16
    • 1970-01-01
    • 2016-07-09
    • 1970-01-01
    相关资源
    最近更新 更多