Linq To Sql Count By Time Brackets - datetime

I need a Linq To SQL Query that Counts the rows of a table that fall within time brackets of an arbitrary interval. The Table has a single DateTime field.
Google got me to this SQL (http://ebersys.blogspot.ca/2010/12/sql-group-datetime-by-arbitrary-time.html)
declare #interval int
set #interval = 5
select convert(varchar(8), DTColumn, 1)+' '
+convert(varchar(2), datepart(hh, DTColumn))+':'
+convert(varchar(2), datepart(mi, DTColumn)/#interval*#interval)
, count(*)
from the_table
group by convert(varchar(8), DTColumn, 1)+' '
+convert(varchar(2), datepart(hh, DTColumn))+':'
+convert(varchar(2), datepart(mi, DTColumn)/#interval*#interval)
I could move the query to SQL but prefer to keep the DAL consistent LinqToSQL. The best I could come up with is this, but errors with "Tick is not supported in SQL"
int interval = Convert.ToInt32(uxTxtInterval.Text);
var q = (from d in dc.theTable.OrderBy(o => o.dmMe).ThenBy(o => o.dmWith).ThenBy(o => o.dmCreatedAt)
group d by
(
Math.Floor(new TimeSpan(d.dmCreatedAt.Ticks).TotalMinutes / interval)
)
into grpTable
select
new
{
time = grpTable.Key, // ?? needs to be the DateTime not ticks
count = grpTable.Count()
}
);
Any help greatly appreciated :-)
Thanks!

You can use SqlMethods.DateDiffMinute to get the time buckets:
var startdate = new DateTime(1900,1,1); // An arbitrary date
int interval = Convert.ToInt32(uxTxtInterval.Text);
var q = (from d in dc.theTable.OrderBy(o => o.dmMe).ThenBy(o => o.dmWith).ThenBy(o => o.dmCreatedAt)
group d by
(
SqlMethods.DateDiffMinute(startdate, d.dmCreatedAt) / interval
)
into grpTable
select
new
{
time = grpTable.Key,
count = grpTable.Count()
}
);

Related

How to select greater number and lower number using LINQ To SQL in C#

I have a TABLE in SQL Database there is a columns in
TABLE ID,Subject,Body,Status,TimeDate in the 400 row data and each i have take a Id as a P_Key and Identity Specification is Yes.
Here is Id = 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 etc..
I want to select greater Id from table based on saved old id like i have saved ID 12 in im getting same id like this with Linq Query below:
public static int CheckId()
{
DataClassesDataContext con = new DataClassesDataContext(Globals.con);
var q = from v in con.TABLE
where v.Id== 12 & v.Status == Active
select v.Id;
foreach (var val in q)
{
return Convert.ToInt32(val);
}
return 0;
}
the i can return a greater id then 12. and there is also one issue. if there is greater ID is Missing from DB example Id 13 is missing then i will get Id 14 in that case. please let me know how can i get id like this i want from db using linq query.
Use Min
return con.<TABLE>
.Where(v=>v.ID > 12)
.Select(v=>v.ID)
.DefaultIfEmpty()
.Min();
I made a sample for you
List<Int32> test = new List<Int32>{1,2,3,4,5,6,7,8,9,10,11,12,14,13,15,16};
var min = test.Where(x=>x>12).Min();
Gives result 13 only, even when 14 is the first bigger
In Your case
//get a table object
Table table = new Table() //if you want whole row.
table = con.Table.Where(x=>x.id>12).MIN();
Based on the code you already have:
DataClassesDataContext con = new DataClassesDataContext(Globals.con);
var q = from v in con.TABLE
where v.Id > 12 & v.Status == Active
orderby v.Id
select v.Id;
return q.Take(1); // to return the whole row
// or
return q.Take(1).Id; // to return only the Id
This would return the first row meeting the criterias (id > 12, status = active). Add error handling code as needed.

Linq to Entity, selecting group with or without value

Hi Need some help with LINQ query.
I have entity called Shift. This entity has several value field but the ones I am intressted in are ShiftID (int), ShiftDate (DateTime) and GrossMount (decimal(10,2). And this needs to be grouped by month (binding this to a graph in ASP.NET).
I need data for the last 12 months grouped by month.
I have come a bit on the way with this post: Linq to Entity, selecting group without value but not quite all the way.
This is my code for now:
public IQueryable<Shift> GetPastMonths(int months, string accountNumber)
{
_context = new EtaxiEnteties();
var _date = DateTime.Today;
var _firstOfMonth = new DateTime(_date.Year, _date.Month, 31);
var _twelveMonthAgoFirstOfMonth = _firstOfMonth.AddMonths(-12);
// Generate a collection of the months and years for the last 12 months
var _monthYears = Enumerable.Range(-12, 12).Select(monthOffset => { var monthDate = _firstOfMonth.AddMonths(monthOffset); return new { y = monthDate.Year, m = monthDate.Month }; });
var _data = (from _monthYear in _monthYears
join _i in
(from _i in _context.Shifts.Where(acc => acc.Account.AccountNumber == accountNumber)
where _i.ShiftDate >= _twelveMonthAgoFirstOfMonth && _i.ShiftDate < _firstOfMonth
group _i by new { y = _i.ShiftDate.Year, m = _i.ShiftDate.Month } into g
select new { ShiftID = g.Key, GrossAmount = g.Count() }) on _monthYear equals _i.ShiftID into j
from _k in j.DefaultIfEmpty()
select new Shift() { ShiftDate = new DateTime(_monthYear.y, _monthYear.m, 1), GrossAmount = _k != null ? _k.GrossAmount : 0 });
return _data as IQueryable<Shift>;
}
Now I have in return a collection of Shift objects, grouped by month but still missing the GrossAmount. Althoug i would need this from today date (only getting from 1 of current month).
Believe this is my main problem: GrossAmount = g.Count(), but I am not sure
Any LINQ specialist out there that could give me a push?
Use GrossAmount = g.Sum(x => x.GrossAmount) to calculate total GrossAmount value of grouped Shift entities. I believe you have typo in GrossAmount (GrossMount) property name.

How to calculate count on of table column using group by clause in linq

I'm new to linq.
In c# I'm doing as follows to get the count of one column.
SELECT DispatcherName,
ActivityType,
CONVERT(BIGINT,COUNT(ActivityType)) AS Total
FROM ACTIVITYLOG
GROUP BY DispatcherName,
ActivityType
ORDER BY Total DESC
Can any one tell m,how I can achieve the same thing using LINQ.
Update:
HI I did as follows and got the reslut.
But I'm not able to convert result to datatable.
this is how I did.
here dt is datatabe with two columns Dispatchername and ActivityType.
var query1 = from p in dt.AsEnumerable()
group p by new
{
DispatcherName = p.Field<string>("Dispatchername"),
Activity = p.Field<string>("ActivityType"),
}
into pgroup
let count = pgroup.Count()
orderby count
select new
{
Count = count,
DispatcherName = pgroup.Key.DispatcherName,
Activity = pgroup.Key.Activity
};
pls help me out asap.
from c in ACTIVITYLOG
group c by new {c.DispatcherName, c.ActivityType} into g
orderby g.Count() descending
select new { g.Key.DispatcherName, g.Key.ActivityType, Total = g.Count() }
If you want your results returned back to a DataTable, one option is to use the CopyToDataTable method.
Here's a live example: http://rextester.com/XHX48973
This method basically requires you to create a dummy table in order to use its NewRow method - the only way to create a DataRow, which is required by CopyToDataTable.
var result = dt.AsEnumerable()
.GroupBy(p => new {
DispatcherName = p.Field<string>("DispatcherName"),
Activity = p.Field<string>("ActivityType")})
.Select(p => {
var row = dummy.NewRow();
row["Activity"] = p.Key.Activity;
row["DispatcherName"] = p.Key.DispatcherName;
row["Count"] = p.Count();
return row;
})
.CopyToDataTable();
Perhaps a better way might be just fill in the rows directly, by converting to a List<T> and then using ForEach.
DataTable dummy = new DataTable();
dummy.Columns.Add("DispatcherName",typeof(string));
dummy.Columns.Add("Activity",typeof(string));
dummy.Columns.Add("Count",typeof(int));
dt.AsEnumerable()
.GroupBy(p => new { DispatcherName = p.Field<string>("DispatcherName"),
Activity = p.Field<string>("ActivityType")})
.ToList()
.ForEach(p => {
var row = dummy.NewRow();
row["Activity"] = p.Key.Activity;
row["DispatcherName"] = p.Key.DispatcherName;
row["Count"] = p.Count();
dummy.Rows.Add(row);
});
Live example: http://rextester.com/TFZNEO48009
This should do the trick:
IList<ACTIVITYLOG> allActivityLogs;
var result = (from c in allActivityLogs
select new
{
DispatcherName = c.DispatcherName,
ActivityType = c.ActivityType,
Total = c.ActivityType.Count
}).OrderByDescending(x => x.Total)
.GroupBy(x => new { x.DispatcherName, x.ActivityType });
You only need to substitute the allActivityLogs collection with the actual collection of your entities.

How do you write a LINQ query that filters a sub table to a specific time period and sums the results of the sub table?

That is the most efficient way to perform a left outer join in LINQ if I must do the following...
Filter Table 2 by a beginning and ending date.
All rows in Table 1 must remain, even if the filtering of Table 2 returns no rows.
The result must be grouped so that the columns from Table 2 get summed.
For example (example code variable names changed for propietary reasons), supposed I have a database with two tables. Table 1 has a list of doors with a building code, door ID and current status (open or closed) - the building code and door ID are the primary key. Table 2 has a list of events for all doors (an event is an opening or closing) plus a timestamp. So the columns are building code, door ID, timestamp, opening, closing. Opening and closing are integers with a 1 in the column for the appropriate event. There is a foreign key relationship between the two tables on the building code and door ID.
For my query I need to return a list of all the unique doors with the current door status and a sum of all the opening and closing events for a selected time period. An entry must be returned for each door, even if no events occured during the selected time period.
Below is the best LINQ code I could come up with. It works, but it seems really inefficient and hard to understand. How would you make it more efficient and easier to understand?
var query =
from doors in Context.Doors
join fevents in
(
from events in db.Events
where events.TimeStamp >= date1 && events.TimeStamp <= date2
select new { events.BuildingCode, events.DoorID, events.TimeStamp, events.Opening, events.Closing }
)
on new { doors.BuildingCode, doors.DoorID } equals { fevents.BuildingCode, fevents.DoorID }
into g1
from c in g1.DefaultIfEmpty()
group c by new
{
doors.BuildingCode,
doors.DoorID,
doors.DoorStatus
} into g2
select new
{
BuildingCode = g2.Key.BuildingCode,
DoorID = g2.Key.DoorID,
Status = g2.Key.DoorStatus
NumOpenings = g2.Sum(i => (i == null ? 0 : i.Opening)),
NumClosings = g2.Sum(i => (i == null ? 0 : i.Closing))
};
I think this is slightly easier to read
var query =
from doors in Context.Doors
from c in db.Events
.Where(events => doors.BuildingCode == events.BuildingCode)
.Where(events => doors.DoorID == events.DoorID)
.Where(events => events.TimeStamp >= date1 && events.TimeStamp <= date2)
.Select(events => new { events.BuildingCode, events.DoorID, events.TimeStamp, events.Opening, events.Closing })
.DefaultIfEmpty()
group c by new
{
doors.BuildingCode,
doors.DoorID,
doors.DoorStatus
} into g2
select new
{
BuildingCode = g2.Key.BuildingCode,
DoorID = g2.Key.DoorID,
Status = g2.Key.DoorStatus
NumOpenings = g2.Sum(i => (i == null ? 0 : i.Opening)),
NumClosings = g2.Sum(i => (i == null ? 0 : i.Closing))
};
The answer from #adducci helped me come up with a slightly different solution that I think is even more readable, albeit possibly less efficient.
var query =
from doors in Context.Doors
from events in doors.Events
.Where(i => i.TimeStamp >= date1 && i.TimeStamp <= date2)
.DefaultIfEmpty()
group new { doors, events }
by doors into g
select new
{
BuildingCode = g.Key.BuildingCode,
DoorID = g.Key.DoorID,
Status = g.Key.DoorStatus,
NumOpenings = g.Sum(i => (i.events == null ? 0 : i.events.Opening)),
NumClosings = g.Sum(i => (i.events == null ? 0 : i.events.Closing))
};
Note that an alternative method for filtering by date would be directly in the summing function, as below, but this is much less efficient since all records would be retrieved from the database and then filtered locally.
...
//from events in doors.Events
// .Where(i => i.TimeStamp >= date1 && i.TimeStamp <= date2)
// .DefaultIfEmpty()
from events in doors.Events
.DefaultIfEmpty()
...
NumOpenings = g.Sum(i => (i.events == null ? 0 : (i.events.Timestamp >= date1 && i.events.TimeStamp <= date2) ? i.events.Opening : 0)),
NumClosings = g.Sum(i => (i.events == null ? 0 : (i.events.Timestamp >= date1 && i.events.TimeStamp <= date2) ? i.events.Closing : 0))
...

LINQ group by and compare date

I have the following:
var currentDate = DateTime.UtcNow;
var calendarEntry = from item in new CalendarEntryRepository(this.Db).List().Where(x => x.Culture == language.Value)
group item by item.ContentObjectId into g
let itemMaxDate = g.Where(i => i.StartDate > currentDate).Select(i => i.StartDate).DefaultIfEmpty()
let city = g.Select(i => i.City).FirstOrDefault()
select new
{
ContentObjectId = g.Key,
StartDate = itemMaxDate,
City = city ?? string.Empty
};
From CalendarEntryRepository I want to group by ContentObjectId (this works fine). However when i add this line:
let itemMaxDate = g.Where(i => i.StartDate > currentDate).Select(i => i.StartDate).DefaultIfEmpty()
I keep getting this error:
Message = "The conversion of a char data type to a datetime data type resulted in an out-of-range datetime value."
What i'm trying to do is group by ContentObjectId and then get StartDate that is greater than today.
I'm using entity framwork and MS SQL2008
thanks
The Min Value of DateTime in your database has a lower value that the MinValue defined int he culture you used in your App.
Change the StartDate column in DataBase to data type DateTime2 to support a broader range of dates

Resources