I'm attempting to write a linq query which uses several tables of related data and have gotten stuck.
The expected result: I need to return the three most populous metropolitan areas per region by population descending.
tables w/sample data:
MetroAreas -- ID, Name
2, Greater New York
Cities -- ID, Name, StateID
1293912, New York City, 10
CityPopulations -- ID, CityID, CensusYear, Population
20, 1293912, 2008, 123456789
21, 1293912, 2007, 123454321
MetroAreaCities -- ID, CityID, MetroAreaID
1, 1293912, 2
States -- ID, Name, RegionID
10, New York, 5
Regions -- ID, Name
5, Northeast
I start with the metro areas. Join the MetroAreaCities to get city IDs. Join Cities to get state IDs. Join States to get the region ID. Join regions so I can filter with a where. I get stuck when I try to include CityPopulations. I only want the three most populous metro areas for a given region. Doing a simple join on the cityPopulations returns a record per year.
(Here's what I have so far, this query was written for SubSonic 3):
return from p in GeoMetroArea.All()
join q in GeoMetroAreaCity.All() on p.ID equals q.MetroAreaID
join r in GeoCity.All() on q.CityID equals r.ID
join s in GeoState.All() on r.StateID equals s.ID
join t in GeoRegion.All() on s.RegionID equals t.ID
where t.ID == regionObjectPassedToMethod.ID
select p;
Can anyone help me with this query or point me in the right direction? Thank you very very much.
I haven't compiled it, but this should get you close:
var regionID = 5;
var year = (from c in GeoCityPopulation.All()
select c.CensusYear
).Max();
var metros =
// States in Region
from s in GeoStateAll()
where s.RegionID == regionID
// Cities in State
join c in GeoCity.All() on s.CityID equals c.ID
// Metro Area for City
join mc in GeoMetroAreaCity.All() on c.ID equals mc.CityID
// Population for City
join cp in GeoCityPopulation.All() on c.ID equals cp.CityID
where cp.CensusYear = year
// Group the population values by Metro Area
group cp.Population by mc.MetroAreaID into g
select new
{
MetroID = g.Key, // Key = mc.MetroAreaID
Population = g.Sum() // g = seq. of Population values
} into mg
// Metro for MetroID
join m in GeoMetroArea.All() on mg.MetroID equals m.ID
select new { m.Name, mg.Population };
Related
I have creatred a query in linqpad and it works but when i try to use it in my blazor app the app throws an error.
I have three tables, tblOpportunity, tblOppStatus and lkpStatus
and an opportunity can have many status's depending on how mature the enquiry is. So i need to get all the latestest status for each opportunity. I also want to be able to filter the dataset so i get only opportunities with staus of x, y and z
void Main()
{
var output=from o in TblOpportunities
join sub in (
//get the latest status ID for the from the joining table
from smax in TblOppStatuses
group smax by smax.OpportunityID
into g
select new
{
OName = g.Key,
MaxS = (from t2 in g select t2.OppStatusID).Max()
})
on o.OpportunityID equals sub.OName
join st in TblOppStatuses on sub.MaxS equals st.OppStatusID
//get the statu sname form the lookup table
join lst in Lkp_Statuses on st.StatusID equals lst.StatusID
join c in TblClients on o.ClientID equals c.ClientID
select new
{
c.ClientName,
o.OpportunityName,
sub.MaxS,
lst.Status,
lst.StatusID
};
int[] filter = { -1, 62};
output.Where(of=>filter.Contains(of.StatusID))
.Dump();
}
The error that comes in the subquery
MaxS = (from t2 in g select t2.OppStatusID).Max()
if i comment this out the query runs but doesn't give me what i want. Can anyone advise what i am doing wrong As I say it works fine in Linqpad.
How could I get this SQL query right in LINQ?
SQL query:
select c.Name, sum(t.value)
from Categories c
join Items i on c.Id = i.CategoryId
join Transactions t on t.ItemId = i.Id
where datepart(YEAR, t.CreatedTime) = 2016
and datepart(MONTH, t.CreatedTime) = 2
group by c.Name
I've tried to do the same in LINQ and got this:
var query = from cat in _context.Categories
join item in _context.Items on cat.Id equals item.CategoryId
join trans in _context.Transactions on item.Id equals trans.ItemId
where trans.CreatedTime.Month == e.RowIndex && trans.CreatedTime.Year == 2016
group new { cat.Name, trans.Value } by cat.Name into g
select new
{
Value = g.Sum(entry => entry.Value)
};
But it seems to be totally wrong, besides not giving me back the category names, it returns wrong values for the sums as well.
I have three tables:
Categories with columns Id and Name
Items with columns Id, Name, CategoryId, LastValue, IsIncome,
Transactions with columns Id, ItemId, Value, CreatedTime, IsIncome
I've this query that i'm trying to put as linq:
select *
from stuff
inner join stuffowner so on so.stuffID = stuff.stuffID
left outer join (select min(loanId) as loanId, stuffownerId from loan
where userid = 1 and status <> 2 group by stuffownerId) t on t.stuffownerid = so.stuffownerid
left outer join loan on t.LoanId = loan.LoanId
when this is done, I would like to do a linq Group by to have Stuff has key, then stuffowners + Loan as value.
I can't seem to get to a nice query without sub query (hence the double left outer).
So basically what my query does, is for each stuff I've in my database, bring the owners, and then i want to bring the first loan a user has made on that stuff.
I've tried various linq:
from stuff in Stuffs
join so in StuffOwners on stuff.StuffId equals so.StuffId
join tLoan in Loans on so.StuffOwnerId equals tLoan.StuffOwnerId into tmpJoin
from tTmpJoin in tmpJoin.DefaultIfEmpty()
group tTmpJoin by new {stuff} into grouped
select new {grouped, fluk = (int?)grouped.Max(w=> w.Status )}
This is not good because if I don't get stuff owner and on top of that it seems to generate a lot of queries (LinqPad)
from stuff in Stuffs
join so in StuffOwners on stuff.StuffId equals so.StuffId
join tmpLoan in
(from tLoan in Loans group tLoan by tLoan.StuffOwnerId into g
select new {StuffOwnerId = g.Key, loanid = (from t2 in g select t2.LoanId).Max()})
on so.StuffOwnerId equals tmpLoan.StuffOwnerId
into tmptmp from tMaxLoan in tmptmp.DefaultIfEmpty()
select new {stuff, so, tmptmp}
Seems to generate a lot of subqueries as well.
I've tried the let keyworkd with:
from tstuffOwner in StuffOwners
let tloan = Loans.Where(p2 => tstuffOwner.StuffOwnerId == p2.StuffOwnerId).FirstOrDefault()
select new { qsdq = tstuffOwner, qsdsq= (int?) tloan.Status, kwk= (int?) tloan.UserId, kiwk= tloan.ReturnDate }
but the more info i get from tLoan, the longer the query gets with more subqueries
What would be the best way to achieve this?
Thanks
I cannot see where the problem lies with the following code. I am trying to retrieve those employees who are named as responsibles for certain vacancie. I have about 20 vacancies in my DB assigned to some 16 employees and about 1801 employee records in the employees table. The code always returns a result with 1801 entries.
from emp in container.Employees
join p in container.Vacancies
on emp.EMPID equals p.ResponsibleOfficer into j
group j by new {k1=emp.EMPID,k2=emp.NAME} into g
select new { EmpId = g.Key.k1, Name = g.Key.k2 , Count = g.Count()}
I want something similar to this
select emp.EmpId,emp.Name,Count(*) as count
from Vacancies p, Employees e
where p.ResponsibleOfficer=e.EmpId
group by e.EmpId,e.Name
any help is much appreciated. thanks
You're using join ... into. That will always return a single result for each element of the original sequence, even if there are no matches in the right sequence.
You can filter out entries with no elements in j using a where clause:
from emp in container.Employees
join p in container.Vacancies
on emp.EMPID equals p.ResponsibleOfficer into j
where j.Any()
group j by new {k1=emp.EMPID,k2=emp.NAME} into g
select new { EmpId = g.Key.k1, Name = g.Key.k2 , Count = g.Count()}
Or you could just use an inner join to start with - but I don't understand your current grouping well enough to see what you're trying to do. What is your group by clause for?
EDIT: If it was really just to group by employee, you're already doing that. You can change the code to:
from emp in container.Employees
join p in container.Vacancies
on emp.EMPID equals p.ResponsibleOfficer into j
where j.Any()
select new { Employee = emp, Count = j.Count()}
Basically, after the join you've got two range variables in scope: emp (the "current" employee) and j (all the relevant vacancies matching that employee). You're just trying to count j for each employee, right?
I'm using lambda, but works:
container
.Employees
.Join(container.Vacancies, l => l.EmpId, e => e.ResponsibleOfficer, (l, e) => new { l.EmpId, l.Name })
.GroupBy(g => new { g.EmpId, g.Name })
.Select(s => new { EmpId = s.Key.EmpId, Name = s.Key.Name, Count = s.Count() });
So I am trying to get a list of cities and the name of the best sold product in each city. There are 3 tables and I cant seem to group them properly and get the count.
Here is what I have so far:
var result9 = (from p in shop.Tb_Purchases
join c in shop.Tb_PreferredCustomer on p.Cust_ID equals c.Cust_ID
join ap in shop.Tb_AvailableProduct on p.Prod_ID equals ap.Prod_ID
group ap by new { c.City, ap.Name } into g
select new { City = g.Key.City, Name = g.Key.Name, NumOf = g.Count() }).ToList();
and this gives me every product sold in each city and how many of them were sold, however i need only one city and the one product that was sold the most in it.
One solution is to group by just the city and then find each city's best product in a subquery.
var result9 = (from p in shop.Tb_Purchases
join c in shop.Tb_PreferredCustomer on p.Cust_ID equals c.Cust_ID
join ap in shop.Tb_AvailableProduct on p.Prod_ID equals ap.Prod_ID
group ap by c.City into g
let largestProductGroup = g.GroupBy(x => x.Name)
.OrderByDescending(x => x.Count())
.First()
select new
{
City = g.Key.City,
Name = largestProductGroup.Key.Name,
NumOf = largestProductGroup.Count()
}).ToList();