Question

I have a database in this format:

Datetime             | Air Temperature
---------------------+-----------------
...                  |
01.12.2013 00:00:00  | 2
01.12.2013 01:00:00  | 2
01.12.2013 02:00:00  | 2
01.12.2013 03:00:00  | 1.7
01.12.2013 04:00:00  | 2
01.12.2013 05:00:00  | 2
01.12.2013 06:00:00  | 2.2
...

and trying to use linq from VB.Net to group the results for each day across a date range:

Dim query = (From i In db _
    Where i.Datetime > #12/1/2013 00:00# AndAlso i.Datetime < #1/1/2014 00:00# _
    Select i).GroupBy(Function(f) f.Datetime.Day)

Console.WriteLine(query)

but query output is grouped by each item in database (each hour) instead day:

[
  {
    "Key": 1,
    "Values": [
      {
        "Datetime": "2013-12-01T00:00:00",
        "AirTemperature": 2.0,
      }
    ]
  },
  {
    "Key": 1,
    "Values": [
      {
        "Datetime": "2013-12-01T01:00:00",
        "AirTemperature": 2.0,
      }
    ]
  },
...

First I used i.DateTime.Date as grouping operator, but as that didn't work the way I wanted, I thought that converting Datetime object to short date string can get me there. It didn't change a thing, and being fresh linq user, I thought to ask for help.

Was it helpful?

Solution

The GroupBy extension method returns an IEnumerable(Of IGrouping(Of TKey,TSource), each IGrouping represents a collection of items and exposes a Key property which in this case will be the date. You can apply a Select to project the groupings and apply Min and Max aggregates to the items, e.g. (Note: as I don't have the database I've set up some example data for the query result):

Structure Item
    Public DateTime As DateTime
    Public Temp As Double
End Structure

Sub Main()
    ' Test data
    Dim query = {
        New Item With {.DateTime = #12/1/2013 00:00#, .Temp = 2},
        New Item With {.DateTime = #12/1/2013 01:00#, .Temp = 2},
        New Item With {.DateTime = #12/1/2013 02:00#, .Temp = 2},
        New Item With {.DateTime = #12/1/2013 03:00#, .Temp = 1.7},
        New Item With {.DateTime = #12/1/2013 04:00#, .Temp = 2},
        New Item With {.DateTime = #12/1/2013 05:00#, .Temp = 2},
        New Item With {.DateTime = #12/1/2013 06:00#, .Temp = 2.2}
    }

    ' Aggregate with extension methods
    Dim aggregated =
        query.GroupBy(Function(item) item.DateTime.Date) _
             .Select(Function(grouping) _
                     New With {
                        .DateTime = grouping.Key,
                        .Max = grouping.Max(Function(item) item.Temp),
                        .Min = grouping.Min(Function(item) item.Temp)
                        })

    ' Aggregate with sugared LINQ
    Dim aggregated2 =
        From item In query
        Group item By key = item.DateTime.Date Into Group
        Select New With {
            .DateTime = key,
            .Min = Group.Min(Function(item) item.Temp),
            .Max = Group.Max(Function(item) item.Temp)}

    ' Show aggregated results
    For Each item In aggregated2
        Console.WriteLine(item.DateTime & " " & item.Min & " " & item.Max)
    Next
End Sub

For reference check out the LINQ Query Samples - Grouping Operators

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top