I have a datatable that I want to query to get the average time difference per groups of Case ID. My data looks as follows.
Name Case ID Incept Time Edit Time
---------------------------------------------------------------------------
Blue 1 2017-02-26T02:35:49-04:00 2017-03-26T02:35:49-04:00
Blue 1 2017-02-26T02:34:49-04:00 2017-04-26T02:35:49-04:00
Blue 1 2017-02-26T02:33:49-04:00 2017-05-26T02:35:49-04:00
Blue 2 2017-02-26T02:32:49-04:00 2017-06-26T02:35:49-04:00
Blue 2 2017-02-26T02:31:49-04:00 2017-07-26T01:35:49-04:00
Blue 2 2017-02-26T02:30:49-04:00 2017-08-26T03:35:49-04:00
Red 5 2017-02-26T02:25:49-04:00 2017-09-26T04:35:49-04:00
Red 5 2017-02-26T02:15:49-04:00 2017-10-26T05:35:49-04:00
Red 1 2017-02-26T02:05:49-04:00 2017-11-26T02635:49-04:00
Red 1 2017-02-26T01:35:49-04:00 2017-12-26T02:35:49-04:00
Red 5 2017-02-26T05:35:49-04:00 2017-12-27T02:35:49-04:00
So far I have the following query which can get into each group of Case ID and get the min and max values.
private IEnumerable<DataRow> _data;
var query =
from data in this._data
group data by data.Field<string>("Name") into groups
select new
{
formName = groups.Key,
caseDiffs =
from d in groups
group d by d.Field<string>("Case ID") into grps
select new
{
min = grps.Min(t =>
DateTimeOffset.ParseExact(t.Field<string>("Incept Time"), "yyyy-MM-ddTHH:mm:sszzzz", CultureInfo.InvariantCulture)
),
max = grps.Max(t =>
DateTimeOffset.ParseExact(t.Field<string>("Edit Time"), "yyyy-MM-ddTHH:mm:sszzzz", CultureInfo.InvariantCulture)
)
}
};
My questions are
1) is it possible to include the difference between the min and max values (per case ID group) to the query
2) At the end how can I get the averages calculated like the diagram below
UPDATED to reflect your changed question...
I've split this into three separate queries so that you can read it more easily (you can combine if you want):
//convert the data using a projection query
var query1 = from data in _data
let inceptTime = DateTimeOffset.ParseExact(data.Field<string>("Incept Time"), "yyyy-MM-ddTHH:mm:sszzzz", CultureInfo.InvariantCulture)
let editTime = DateTimeOffset.ParseExact(data.Field<string>("Edit Time"), "yyyy-MM-ddTHH:mm:sszzzz", CultureInfo.InvariantCulture)
let difference = editTime - inceptTime
select new
{
name = data.Field<string>("Name"),
caseId = data.Field<string>("Case ID"),
inceptTime,
editTime,
difference
};
//group by caseID (also by NAME, but that won't matter for this grouping and is needed in query3)
var query2 = from data in query1
group data by new { data.caseId, data.name } into groups
let min = groups.Min(x => x.inceptTime)
let max = groups.Max(x => x.editTime)
select new
{
name = groups.Key.name,
caseId = groups.Key.caseId,
min,
max,
diff = max - min
};
//now group by name
var query3 = from data in query2
group data by new { data.name } into groups
select new
{
name = groups.Key.name,
minDiff = groups.Min(x => x.diff),
maxDiff = groups.Max(x => x.diff),
avgDiff = new TimeSpan((long)groups.Average(x => x.diff.Ticks)),
};
NOTE: The "edit time" for the 9th record is in an invalid format
You just need to define a few let variables in your LINQ query. About 3 more lines, in fact. Your grouping LINQ should look like this:
var query =
from data in this._data
group data by data.Field<string>("Name") into groups
select new
{
formName = groups.Key,
caseDiffs = from d in groups group d by d.Field<string>("Case ID") into grps
// three variables here, so that you can do the
// date math that you require!
let minDt = caseGroup.Min(t =>
DateTimeOffset.ParseExact(t.Field<string>("Incept Time"),
"yyyy-MM-ddTHH:mm:sszzzz", CultureInfo.InvariantCulture)
let maxDt = grps.Max(t =>
DateTimeOffset.ParseExact(t.Field<string>("Edit Time"),
"yyyy-MM-ddTHH:mm:sszzzz", CultureInfo.InvariantCulture)
let diffInSecs = (maxDt - minDt).TotalSeconds
select new
{
min = minDt,
max = maxDt,
diff = diffInSecs
}
};
Hope that helps!
Related
How to calculate sum of timedifference and average using linq let method, I tried below mentioned code it's return timedifference list only.
var query1 = from c in DBCollection.Find(Query_Collection).ToList()
let DtCreateDate = Convert.ToDateTime(c["CreatedDate"])
let DtModifiedDate = Convert.ToDateTime(c["LastModifiedDate"])
let difference = (DtModifiedDate - DtCreateDate).TotalSeconds select new { difference };
By doing the following:
var query1 = from c in DBCollection.Find(Query_Collection).ToList()
let DtCreateDate = Convert.ToDateTime(c["CreatedDate"])
let DtModifiedDate = Convert.ToDateTime(c["LastModifiedDate"])
let difference = (DtModifiedDate - DtCreateDate).TotalSeconds
let averageSum = (((DtCreateDate + DtModifiedDate) / 2) + difference) //calculate the average
select new { difference, averageSum };
Above, the 'difference' between two given dates is saved in the variable difference.
I have added another variable called 'averageSum', that now stores the value of the average between the two dates, and then adds the difference to the average.
I've don't understund how you calculate average for every row, but to accumulate custom values you can use Aggregate method as shown below:
var query1 = from c in DBCollection.Find(Query_Collection).ToList()
.Select(e => new {DtCreateDate = Convert.ToDateTime(e["CreatedDate"]), DtModifiedDate = Convert.ToDateTime(e["LastModifiedDate"])})
.Select(e => new {Diff = (e.DtModifiedDate - e.DtCreateDate).TotalSeconds, Av = 0 /* Calculate average for the row */} )
.Aggregate(new {Diff = (double) 0, Av = 0}, (group, cur) => new {Diff = group.Diff + cur.Diff, Av = group.Av + cur.Av});
Result of the statement is a single object which contais sums for difference and average on the whole list
I have this collection of GroupedResult
IQueryable<GroupedResult> groupedResult = from p in db.Departure
group p by new { p.Terminal, p.DepartureDate, p.DepartureDate.Month } into g
select new GroupedResult
{
terminal = g.Key.Terminal.Code,
date = g.Key.DepartureDate,
distance = g.Count(),
month = g.Key.Month
};
The problem is that the collection I get has some dates missing. For example db.Departure contains Feb. 1, 2, 4, and 6. I also wanted to show GroupedResult for Feb. 3 and 5 so I use the following code to create a collection of dates starting from a particular start date:
var dates = new List<DateTime>();
for (var dt = date; dt <= DateTime.Now; dt = dt.AddDays(1))
{
dates.Add(dt);
}
And then join dates with groupedResult
var result = from p in groupedResult.ToList()
from q in dates.Where(r => r == p.date).DefaultIfEmpty()
select p;
The result I get is same as the one with groupedResult. How can I also show the entries with no date data?
This is because you are selecting P at the very end.....you have to create new anonymous class
var result = from q in dates
join p in groupedResult.ToList() on q equals p.date into joinedResult
from r in joinedResult.DefaultIfEmpty()
select new
{
terminal = r==null?null:r.terminal,
date = q,
distance = r==null?null:r.distance,
month = r==null?null:r.month
};
var result = from p in groupedResult.ToList()
from q in dates.Where(r => r == p.date).DefaultIfEmpty()
select p;
You've got the left join the wrong way around. You're selecting all items from your groupedResult and then ask LINQ to get all dates - or none if there is none - that match a date that already exists in the groupedResult.
var result = from q in dates
from p in groupedResult.Where(r => r.date == q).DefaultIfEmpty()
select new { Date = q, Items = p };
This works, because you select all dates and search for matching grouped items instead.
Here unoinColumn is return the all the date with out duplicate but i want to get the date group by month
month totalamount
7/2014 10000
8/2014 10000
enter code here var unoinDateColumn = (from agent in db.collections
where agent.Date_Time.Value.Year == thisYear
select agent.Date_Time).Union(from u in db.bank_deposit
where u.Date_Time.Value.Year == thisYear
select u.Date_Time).ToList();
You can do something like that, if I understood well.
Filter collections and deposits by given year, select date_time and amount
Union, group by month, select date in the desired format, and sum amount.
You can of course do all that in one query, but I'm not sure this will be easier to read ;)
var collections = db.Collections.Where(x => x.Date_Time.Value.Year == thisYear)
.Select(m => new {
dt = m.Date_Time.Value,
amount = m.Amount
});
var deposits = db.Collections.Where(x => x.Date_Time.Value.Year == thisYear)
.Select(m => new {
dt = m.Date_Time.Value,
amount = m.Amount
});
var result = collections.Union(deposits)
.GroupBy(m => m.dt.Month)
.Select(g => new {
date = g.First().dt.ToString("MM/yyyy"),
totalAmount = g.Sum(x => x.amount)
});
I have a simple linq query that I'm trying to extend so that I can first sum all the values in the VoteCount field and then for each Nominee I want to assign what percentage of votes the nominee received.
Here's the code:
TheVoteDataContext db = new TheVoteDataContext();
var results = from n in db.Nominees
join v in db.Votes on n.VoteID equals v.VoteID
select new
{
Name = n.Name,
VoteCount = v.VoteCount,
NomineeID = n.NomineeID,
VoteID = v.VoteID
};
Since selecting the single votes for each nominee and calculating the sum of all votes are two different tasks, I cannot think of a way of doing this efficiently in one single query. I would simply do it in two steps, as
var results = from n in db.Nominees
join v in db.Votes on n.VoteID equals v.VoteID
select new
{
Name = n.Name,
VoteCount = v.VoteCount,
NomineeID = n.NomineeID,
VoteID = v.VoteID
};
var sum = (decimal)results.Select(r=>r.VoteCount).Sum();
var resultsWithPercentage = results.Select(r=>new {
Name = r.Name,
VoteCount = r.VoteCount,
NomineeID = r.NomineeID,
VoteID = r.VoteID,
Percentage = sum != 0 ? (r.VoteCount / sum) * 100 : 0
});
You could also calculate the sum before the results (using an aggregate query), this would leave the task of summing to the Database engine. I believe that this would be slower, but you can always find out by trying :)
How can I execute the following SQL-Query using LINQ or HQL?
SELECT `year`, `month`, COUNT(code_id)
FROM (SELECT DISTINCT request_codes_id AS code_id,
YEAR(requested) AS `year`, MONTH(requested) AS `month` FROM requests) r
GROUP BY `year`, `month`
ORDER BY `year`, `month`;
I tried the following:
var items = from r in TestaccountRequest.Queryable
group r by r.RequestCodeId into g
select g.First();
var grouped = from r in items
group r by r.Requested.ToString("yyyyMM") into y
select new { Year = y.First().Requested.Year, Month = y.First().Requested.Month, Count = y.Count() };
which threw a System.String ToString(System.String) NotSupportedException.
UPDATE:
The g.First() in the first LINQ-Query seems to cause the problem, because if I only run the first one I get a Code supposed to be unreachable-Exception, but if I remove the .First() it "works", but does not return what I need.
Group by an anonymous type instead:
var grouped = from r in items
group r by new { Year = r.Requested.Year,
Month = r.Requested.Month } into g
select new { g.Key.Year, g.Key.Month, Count = g.Count() };
I kinda solved it using the following:
var items = from r in TestaccountRequest.Queryable
group r by r.RequestCodeId into g
select g.ElementAt(0);
var grouped = from r in items.ToList()
group r by new { Year = r.Requested.Year,
Month = r.Requested.Month } into g
select new { g.Key.Year, g.Key.Month, Count = g.Count() };
but I gues thats not the best solution as all objects are getting fetched from the DB, but at least it is working for now, but please provide a better solution if available.
EDIT:
I now solved it using HQL:
HqlBasedQuery query = new HqlBasedQuery(typeof(ActivationCodeTestaccountRequestRecord),
"SELECT DISTINCT r.ActivationCodeId, YEAR(r.Requested), MONTH(r.Requested) " +
"FROM ActivationCodeTestaccountRequestRecord r");
var items = from object[] row in (ArrayList)ActiveRecordMediator.ExecuteQuery(query)
group row by new { Year = row[1], Month =row[2] } into g2
select new { Year = g2.Key.Year, Month = g2.Key.Month, Count = g2.Count() };