如何在 SQL Azure 中使用 Entity Framework 平均 DateTime 值?

How do I average DateTime values in SQL Azure with Entity Framework?

我有一个 SQL 查询需要在服务器端(在 SQL 服务器中)计算许多日期时间值的平均值。出于举例的目的,我们只考虑它是一个像这样的简单查询,在 table 上有数百万条记录:

SELECT
    SomeField,
    AVG(CAST(ADateTime AS decimal(18,8))) AS NumericRepresentation
FROM MyTable
GROUP BY SomeField

如图所示,我不能简单地采用 AVG(ADateTime) 因为 SQL 服务器不喜欢这样做,而是将其转换为 Decimal(然后将其转换回 DateTime)对我来说效果很好。

做与 EntityFramework 相当的事情的明显方法是使用 .Select(tbl => tbl.ADateTime.Ticks).Average(),但这在运行时失败,因为 DateTime.Ticks 不通过 Linq-to-Entities 转换。

我应该怎样做才能最好?我的主要需求是以某种方式平均日期时间值。只要可以在 SQL 或 .NET 代码中将其转换回 DateTime,临时表示(小数、刻度等)就不是特别重要。但重要的是,平均是在 SQL 服务器中完成的(我对许多记录进行了一些相当复杂的计算)并且我可以以某种方式在 .NET 中获得翻译的 DateTime(无论翻译是否发生在 SQL 服务器或 .NET,我不在乎)。

EF LINQ 表达式可以利用 SqlFunctions class 来确保转换正确发生。

DateTime minDate = new DateTime(1900,1,1);
var avg = MyTable.Select(myrow => SQLFunctions.DateDiff("second",myrow.ADateTime,minDate).Average();
DateTime avgDate = minDate.AddSeconds(avg);

之前的回答,请忽略:

使用Convert.ToDoubleEntityFramework 应该能够翻译这个 LINQ to SQL 能够 CONVERT(float,...) 只要你的专栏实际上是 DateTime 而不是 DateTime2DateTimeOffset, 但不幸的是 Entity Framework 无法识别此结构。

.Select(tbl => Convert.ToDouble(tbl.ADateTime)).Average()

另一种选择是在客户端进行:

.Select(tbl => tbl.ADateTime).ToArray().Select(dt => dt.Ticks).Average()

虽然如果您对数百万行求平均值,显然这不是首选。

在纯 SQL 中,您可以使用类似这样的方法在日期字段上求平均值:

-- the smallest date you could possibly have in your data
DECLARE @MinDate DATE = '1/1/1900' 
SELECT
    SomeField,
    DATEADD(DAY, AVG(DATEDIFF(DAY, @MinDate, ADateTime)), @MinDate) as AvgDateTime
FROM MyTable
GROUP BY SomeField

还不确定如何将其转换为 LINQ :)

更新: 这是 LINQ 代码:

private static void Test(IQueryable<SomeClass> data)
    {
        var minDate = DateTime.MinValue;
        var avgMilliseconds = data.Select(x => x.SomeDateField.Subtract(minDate).TotalMilliseconds).Average();
        var avgDate = minDate.AddMilliseconds(avgMilliseconds);
        Console.WriteLine(avgMilliseconds);
        Console.WriteLine(avgDate);
    }