复杂的SQL JOIN查询,最小值,最大值和日期范围

时间:2014-12-23 17:43:22

标签: c# sql-server database linq entity-framework

我有以下表格:

Readings:
+----+---------------------+-------+----------+
| Id |   TimestampLocal    | Value | Meter_Id |
+----+---------------------+-------+----------+
|  1 | 2014-08-22 18:05:03 | 50.5  |        1 |
|  2 | 2013-08-12 14:02:09 | 30.2  |        1 |
+----+---------------------+-------+----------+

Meters:
+----+--------+
| Id | Number |
+----+--------+
|  1 |  32223 |
+----+--------+

我需要为每个仪表选择2个读数,最大日期时间读数和最小日期时间读数,以及两个读数值之间的差异,如下所示:

+----------+------------+----------------+------------+----------------+------------+
| Meter_Id | MaxReading | MaxReadingTime | MinReading | MinReadingTime | Difference |
+----------+------------+----------------+------------+----------------+------------+

我需要一个查询来实现实体框架

中日期范围内的所有米

我能够达到这个目标(获得最大和最小读数):

SELECT 
    tt.*
FROM Readings tt
INNER JOIN
    (
    SELECT 
        Meter_Id, 
        MAX(TimeStampLocal) AS MaxDateTime, 
        MIN(TimeStampLocal) AS MinDateTime
    FROM Readings 
    where TimeStampLocal > '2014-12-08'
    GROUP BY Meter_Id
    ) AS groupedtt 
ON (tt.Meter_Id = groupedtt.Meter_Id)   AND 
    (tt.TimeStampLocal = groupedtt.MaxDateTime or tt.TimeStampLocal = groupedtt.MinDateTime) 
order by Meter_Id;

2 个答案:

答案 0 :(得分:1)

使用您的实际架构和数据的这个模型:

class Reading
{
    public int Id { get; set; }
    public DateTime TimestampLocal { get; set; }
    public double Value { get; set; }
    public int Meter_Id { get; set; }
}

List<Reading> Readings = new List<Reading>()
{
    new Reading { Id = 1, TimestampLocal = new DateTime(2014, 8, 22), Value = 50.5, Meter_Id = 1 },
    new Reading { Id = 2, TimestampLocal = new DateTime(2013, 8, 12), Value = 30.2, Meter_Id = 1 },
    new Reading { Id = 3, TimestampLocal = new DateTime(2013, 9, 12), Value = 35.2, Meter_Id = 1 }
};

使用此linq查询:

        var q = from r in Readings
                group r by r.Meter_Id into rGroup
                select new
                {
                    Meter_Id = rGroup.Key,
                    MaxReading = rGroup.OrderByDescending(x => x.TimestampLocal).First().Id,
                    MaxReadingTime = rGroup.OrderByDescending(x => x.TimestampLocal).First().TimestampLocal,
                    MinReading = rGroup.OrderBy(x => x.TimestampLocal).First().Id,
                    MinReadingTime = rGroup.OrderBy(x => x.TimestampLocal).First().TimestampLocal,
                    Difference = rGroup.OrderByDescending(x => x.TimestampLocal).First().Value -
                                 rGroup.OrderBy(x => x.TimestampLocal).First().Value
                };

生成此输出:

[0] = { Meter_Id = 1, MaxReading = 1, MaxReadingTime = {22/8/2014 12:00:00 πμ}, 
        MinReading = 2, MinReadingTime = {12/8/2013 12:00:00 πμ}, Difference = 20.3 }

应该接近预期的结果。

修改

您可以通过使用let子句来大大简化上述linq查询:

var q = from r in Readings
        group r by r.Meter_Id into rGroup
        let MaxReading = rGroup.OrderByDescending(x => x.TimestampLocal).First()
        let MinReading = rGroup.OrderBy(x => x.TimestampLocal).First()
        select new
        {
            Meter_Id = rGroup.Key,
            MaxReading = MaxReading.Id,
            MaxReadingTime = MaxReading.TimestampLocal,
            MinReading = MinReading.Id,
            MinReadingTime = MinReading.TimestampLocal,
            Difference = MaxReading.Value - MinReading.Value
        };

答案 1 :(得分:0)

我承认,可能效率不是最高效的,但这是最快的,我可以拿出一些东西,而不是自己反击验证。

SELECT m.Id AS Meter_Id, MaxReading, MaxReadingTime, MinReading, MinReadingTime, (MaxReading - MinReading) AS Difference
FROM Meters m
CROSS APPLY (SELECT MIN(Value) MinReading, TimestampLocal AS MinReadingTime FROM Readings WHERE Meter_Id = m.Id) min
CROSS APPLY (SELECT MAX(Value) MaxReading, TimestampLocal AS MaxReadingTime FROM Readings WHERE Meter_Id = m.Id) max

编辑:格式化。