LINQ left outer join on date not working - c#

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.

Related

Group record by hour in Enity Framwork and fill gaps

There was a similar question before Grouping records hour by hour or day by day and filling gaps with zero or null and Grouping records hour by hour or day by day and filling gaps with zero or null in mysql but both solutuion use SQL. I would like to resolve this problem with code.
The easiest solution is to run:
var q = from i in XXX.Table
let dt = p.Date
group i by new { y = dt.Year, m = dt.Month, d = dt.Day, h = dt.Hour}
select g;
but I have got a lot of gaps still to fill.
You can fetch groups from server and fill gaps on client:
var startDate = new DateTime(2014, 1, 2);
var endDate = new DateTime(2014, 1, 3);
var dict = (from c in YourTable
where c.YourDate >= startDate && c.YourDate <= endDate
let hours = DbFunctions.DiffHours(startDate, c.YourDate)
group c by hours into g
select new {Hour = g.Key, Count = g.Count()}).ToDictionary(r => r.Hour.Value, r => r.Count);
var result = Enumerable.Range(0, (int)(endDate - startDate).TotalHours).Select(h => new {Date = startDate.AddHours(h), Count = dict.ContainsKey(h) ? dict[h] : 0});

LINQ query to group records by month within a period

I am looking for some help on adapting the following LINQ query to return all dates within the next 6 months, even those where no records fall within the given month.
var maxDate = DateTime.Now.AddMonths(6);
var orders = (from ord in db.Items
where (ord.Expiry >= DateTime.Now && ord.Expiry <= maxDate)
group ord by new
{
ord.Expiry.Value.Year,
ord.Expiry.Value.Month
}
into g
select new ExpiriesOwnedModel
{
Month = g.Select(n => n.Expiry.Value.Month).First(),
Quantity = g.Count()
}).ToList();
I'd really appreciate any assistance or pointers on how best to implement this.
I'm not sure how well it'll interact with your database, but I'd do this as with a join:
var firstDaysOfMonths = Enumerable.Range(0, 7).Select(i =>
new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(i));
var orders = firstDaysOfMonths.GroupJoin(
db.Items,
fd => fd,
ord => new DateTime(ord.Expiry.Value.Year, ord.Expiry.Value.Month, 1),
(fd, ords) => new { Month = fd.Month, Quantity = ords.Count() });
Note you may end up with an extra month where before you didn't (on the first day of the month?)
Stolen from Rawling's answer, if you prefer query syntax for group joins (I do):
var orders =
from month in Enumerable.Range(0, 7)
.Select(i => new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(i))
join ord in db.Items
on month equals new DateTime(ord.Expiry.Value.Year, ord.Expiry.Value.Month, 1)
into ords
select new { month.Month, Quantity = ords.Count() };
Alternative if it does not play nice with the database:
var rawGroups = db.Items.Where(item.Expiry >= DateTime.Now && ord.Expiry <= maxDate)
.GroupBy(item => new
{
item.Expiry.Value.Year,
item.Expiry.Value.Month
}, g => new ExpiriesOwnedModel()
{
Month = g.Key.Month,
Quantity = g.Count()
}).ToDictionary(model => model.Month);
var result = Enumerable.Range(DateTime.Now.Month,6)
.Select(i => i > 12 ? i - 12 , i)
.Select(i => rawGroups.Keys.Contains(i) ?
rawGroups[i] :
new ExpiriesOwnedModel()
{ Month = i , Quantity = 0 });

How to distinct select and group with castle active records?

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

Linq Merge Queries

I have two queries that I would like to merge. This might be a left outer join, but it seems different.
The first query selects distinct stuff from a table:
var d = from d in db.Data
select (d.ID, d.Label, Value = 0).Distinct;
Lets suppose this returns the following:
{1,"Apple",0}
{2,"Banana",0}
{3,"Cabbage",0}
I then have another query that makes a different selection:
var s = from d in db.Data
where d.Label != "Apple"
select (d.ID, d.Label, d.Value);
This returns:
{2,"Banana",34}
{3,"Cabbage",17}
I then want a third query that joins the d and s together based upon their ID and their Label. I want the result to look like this:
{1,"Apple",0}
{2,"Banana",34}
{3,"Cabbage",17}
I'm basically just updating the numbers in the third query, but I have no idea how I should be doing this. It feels like it should be a simple join, but I just cannot get it to work.
This should work:
var query1 = from d in db.Data
select new { d.ID, d.Label, Value = 0 }.Distinct();
var query2 = from d in db.Data
where d.Label != "Apple"
select new { d.ID, d.Label, d.Value };
var result =
from d1 in query1
join d2 in query2 on new { d1.ID, d1.Label } equals new { d2.ID, d2.Label } into j
from d2 in j.DefaultIfEmpty()
select new
{
d1.ID,
d1.Label,
Value = d2 != null ? d2.Value : d1.Value
};
Note: are you sure you want to join on the ID and the label ? It seems rather strange to me... the label shouldn't be part of the key, so it should always be the same for a given ID
Here is one using method chain, which is my personal favorite.
var one = db.Data.Select(f => new {f.Id, f.Label, Value = 0});
var two = db.Data.Select(f => f).Where(f => f.Label != "Apple");
var three = one.Join(two, c => c.Id, p => p.Id, (c, p) => new {c.Id, c.Label, p.Value});
Could you just do
var s = from d in db.Data
select new
{
Id = d.ID,
Label = d.Label,
Value = (d.Label == "Apple" ? 0 : d.Value)
};

Linq query with left join and group

I'm unable to convert this SQL query into a working linq statement
select sum(cena), id_auta, max(servis)
from dt_poruchy left outer join mt_auta on dt_poruchy.id_auta=mt_auta.id
where dt_poruchy.servis>=3 group by id_auta;
I tryed something like this but i cant handle the select statement
var auta = from a in MtAuta.FindAll()
join p in DtPoruchy.FindAll() on a equals p.MtAuta into ap
from ap2 in ap.DefaultIfEmpty()
where ap2.SERVIS >= 3
group ap2 by ap2.ID into grouped
select new {
I'll appreciate any help!
Based on the limited information provided (which tables are certain fields from?), here is what I came up with.
var auta = from a in MtAuta.FindAll()
let p = a.DtPoruchys.Where(s => s.SERVIS >= 3)
select new
{
Id = a.Id,
CenaSum = p.Sum(c => c.Cena),
Servis = p.Max(s => s.SERVIS)
};
I've reached this solution (supposing "cena" belongs to MtAuta.FindAll()):
var auta = from e in
(from a in DtPoruchy.FindAll()
where a.SERVIS >= 3
join p in MtAuta.FindAll() on a.MtAuta equals p.Id into ap
from ap2 in ap.DefaultIfEmpty()
select new
{
Cena = ap.cena,
IdAuta = a.MtAuta,
Servis = a.servis
})
group e by e.IdAuta into g
select new
{
Cena = g.Sum(e => e.cena),
IdAuta = g.Key,
Servis = g.Max(e => e.servis)
};
I am not sure which table cena and servis are coming from but to create grouped sum you do something like.
select new { Sum = grouped.Sum( x => x.cena ) }
and to get max
select new { Max = grouped.Group.Max( x => x.servis ) }
Here is a good reference for you.
MSDN - 101 LINQ Samples
I've modified your solution little bit and i got it working like this:
var auta = from jo in
(
from a in MtAuta.FindAll()
join p in DtPoruchy.FindAll() on a equals p.MtAuta into ap
from ap2 in ap.DefaultIfEmpty()
where ap2.SERVIS >= 3
select new
{
Cena = ap2.CENA,
Idauto = ap2.ID_AUTA,
Servis = ap2.SERVIS
}
)
group jo by jo.Idauto into g
select new
{
Cena = g.Sum(jo => jo.Cena),
IdAuto = g.Key,
Servis = g.Max(jo => jo.Servis)
};
I just curious if this is the best solution?

Categories

Resources