简体   繁体   English

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

[英]Complex SQL JOIN Query, min, max and date range

I have the following tables: 我有以下表格:

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 |
+----+--------+

I need to select 2 readings for each meter, the reading with max DateTime and the reading with min DateTime, in addition to the difference between values of the two readings, something like this: 我需要为每个仪表选择2个读数,除了两个读数值之间的差异外,最大日期时间的读数和最小日期时间的读数,如下所示:

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

I need a single query to achieve this for all meters within a date range in Entity Framework 我需要一个查询来针对Entity Framework中的日期范围内的所有仪表实现此目的

i was able to get this far (get max and min readings): 我能够做到这一点(获取最大和最小读数):

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;

Using this mockup of your actual schema and data: 使用您的实际模式和数据的此模型:

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 }
};

using this linq query: 使用此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
                };

produces this output: 产生以下输出:

[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 }

which should be close to expected result. 应该接近预期的结果。

EDIT: 编辑:

You can considerably simplify the above linq query by making use of the let clause: 您可以通过使用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
        };

Probably not the most efficient, I admit, but that's the quickest I could come up with something without counter-verifying it myself. 我承认,这可能不是最有效的方法,但这是我想出的最快方法,而无需自己对它进行验证。

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

edit: formatting. 编辑:格式化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM