-2

I am getting the 'interval' wise (30 min, 15 min, 45 min) data in my stored procedure now I want to combine the 'time slot' of (30 min, 15 min, 45 min, etc.) and do the 'addition' of above column.

e.g Existing procedure output:

 Time   Parameter 1     Parameter 2     Parameter 3
  ----------------------------------------------------
    8:00    7.6                2                  0
    8:30    7.52               2                  0
    9:00    20.6               1                  0
    9:30    5.57               1                  0
    10:00   5.43               1                  0
    10:30   5.78               1                  0
    11:00   8.09               1                  0
    11:30   10.48              1                  0
    12:00   10.11              1                  0
    12:30   9.95               0                  0
    13:00   6                  1                  0
    13:30   5.08               0                  0
    14:00   5.31               0                  0
    14:30   20.38              0                  0
    15:00   6.17               0                  0

And I want to be as :

Time-slot            Parameter 1     Parameter 2  Parameter 3
-------------------------------------------------------------
8:00:00 - 8:30:00       15.12           4                0
8:30:00 - 9:00:00       28.12           3                0
9:00:00 - 9:30:00       26.17           2                0
9:30:00 - 10:00:00        11            2                0
10:00:00 - 10:30:00      11.21          2                0
10:30:00 - 11:00:00      13.87          2                0
11:00:00 - 11:30:00      18.57          2                0
11:30:00 - 12:00:00      20.59          2                0
12:00:00 - 12:30:00      20.06          1                0
12:30:00 - 13:00:00      15.95          1                0
13:00:00 - 13:30:00      11.08          1                0
13:30:00 - 14:00:00      10.39          0                0
14:00:00 - 14:30:00      25.69          0                0
14:30:00 - 15:00:00      26.55          0                0
ssd
  • 45
  • 6
  • 1
    Do you really want to "double count" the 8:30 value in both 8:00 - 8:30 and 8:30 - 9:00? If I saw data like that I would expect only one end of each range to be inclusive, so the sum of the column would be the same as the sum of the raw data. Also is the 15:01 not being on a boundary significant, or just a typo? – James Casey Jul 19 '19 at 12:46
  • How is 15:01 in the 14:30-15:00? Where is a value on s plait time? Is 12:30 value in the lower or upper part? – xdtTransform Jul 19 '19 at 12:47
  • @JamesCasey it was just sample data and I want to the addition of that timeslots of columns param1,param2,param3 – ssd Jul 19 '19 at 12:51
  • @xdtTransform it was by mistake I will update it – ssd Jul 19 '19 at 12:53
  • First I will take the Max/Min Date and round them so i have the maximum range: from 8:12-19:23 to 8:00-19:30. then use something like [that](https://stackoverflow.com/questions/13690617/split-date-range-into-date-range-chunks) to generate all the range inside. Next step is just group data . – xdtTransform Jul 19 '19 at 12:55
  • If the data is already in "30 minute intervals", then 08:00 already means 08:00 - 08:30 (or possibly 07:30 - 08:00). So there is no aggregation to do, just make a nice looking column name with CONVERT(VARCHAR, [TIME], 120) + ' - ' + CONVERT(VARCHAR,DATEADD(minute, 30, [Time]),120) – James Casey Jul 19 '19 at 13:14
  • What have you tried so far, and what was the result? Most folks here are happy to help, but SO isn't a coding service. – Brian Jul 19 '19 at 14:05

1 Answers1

1

1/. Find the range you are working on.

  • Round Up the maximum date from your data to your define interval.
  • Round Down the minimum from your data to your define interval.

 

public static DateTime RoundUp(DateTime dt, TimeSpan d)
   => new DateTime((dt.Ticks + d.Ticks - 1) / d.Ticks * d.Ticks, dt.Kind);

public static DateTime RoundDown(DateTime dt, TimeSpan d)
    => new DateTime(dt.Ticks - (dt.Ticks % d.Ticks), dt.Kind);

Edit:
With this RoundDown if your minimum is on a split time, no previous interval will be created.
E.g for 8:00, the minimum interval is {8:00-8:30} not {7:30-8:00}, {8:00-8:30}

Reference:


2/. Split the range into sub-range of your interval.

Example: from 8 to 9, in interval of 30min, is {{8-8:30}, {8:30-9}}

public static IEnumerable<Range<DateTime>> SplitDateRange(DateTime start, DateTime end, TimeSpan ChunkSize)
{
    DateTime chunkEnd;
    while ((chunkEnd = start.Add(ChunkSize)) < end)
    {
        yield return new Range<DateTime>(start, chunkEnd);
        start = chunkEnd;
    }
    yield return new Range<DateTime>(start, end);
}


Using Range:
Range is a pretty basic thing, normally you have two variables (start/end) and write the same comparaison other and other. Here we abstract it away and apply it on class that implement IComparable, so we can easly sort our range. And provide 2 methods to know: If a object is in the range. Or if 2 ranges overlaps.

public struct Range<T> where T : IComparable<T>
{
    public Range(T start, T end)
    {
        Start = start;
        End = end;
    }

    public T Start { get; }
    public T End { get; }
    public bool Includes(T value) 
        => Start.CompareTo(value) <= 0 && End.CompareTo(value) >= 0;
    public bool Includes(Range<T> range) 
        => Start.CompareTo(range.Start) <= 0 && End.CompareTo(range.End) >= 0;
}

Reference:


3/. "Multiply the value".

As you need split Value to be in two range: 8:30 is in range {8:00-8:30} and {8:30-9:00}

We will make a cartesian product of your date and the range and pair them based on of the date beeing in the range.

var temp = from i in input            // For all i in input
           from r in ranges           // For all range
           where  r.Includes(i.Date)  // If the input date is in a range
           select new                 // We create a new entry 
                      {
                          Range = r,
                          Field1 = i.Field1,
                          Field2 = i.Field2,
                          Field3 = i.Field3
                      };

4/. GroupBy and Sum.

Finaly a simple GroupBy and Sum

var result = 
    temp .GroupBy(x => x.Range))
          .Select(g =>
              new
              {
                  Range = g.Key,
                  SumField1 = g.Sum(x => x.Field1),
                  SumField2 = g.Sum(x => x.Field2),
                  SumField3 = g.Sum(x => x.Field3)
              })
           .ToList();

Reference:


live demo in this demo no extention class have been create in order to put everything in the main.
xdtTransform
  • 1,986
  • 14
  • 34