I've got the following query.
SELECT *
FROM Movie m INNER JOIN
(
SELECT movie_id, COUNT(movie_id) as amount
FROM Watchhistory
WHERE watch_date >= DATEADD(day,-3000, GETDATE())
GROUP BY movie_id
) as a on m.movie_id = a.movie_id
ORDER BY a.amount DESC
And the following tables:
My attempt right now:
var movies = _context.Movie
.AsNoTracking()
.Join(
_context.Watchhistory.Where(
w => w.WatchDate >= Convert.ToDateTime(DateTime.Now).AddDays(-14))
.GroupBy(w => w.MovieId)
.Select(m => new { amount = m.Count(), mID = m.Key })
.OrderByDescending(a => a.amount)
.Select(a => new { movieid = a.mID }),
m => m.MovieId, w => w.movieid, (m, w) => m);
I cant seem to get it working in c# dotnet entity. How do I use a right outer join in linq?
You rarely use JOIN in LINQ. Instead just write queries navigate the model.
so
SELECT *
FROM Movie m INNER JOIN
(
SELECT movie_id, COUNT(movie_id) as amount
FROM Watchhistory
WHERE watch_date >= DATEADD(day,-3000, GETDATE())
GROUP BY movie_id
) as a on m.movie_id = a.movie_id
ORDER BY a.amount DESC
becomes something like:
var q = from m in db.Movies
select new {m.MovieID,m.Name, amount = m.WatchHistory.Where( w => w.WatchDate >= ...).Count() };
var results = q.Where( m => m.amount > 0).OrderByDesc( m => m.amount).ToList();
David
Related
I'm translating a query and here's the original:
select top 5 t.usrID, u.FirstName, u.LastName, t.cnt as sCount
from (
select usrID, COUNT(rID) as cnt
from sessions as s where s.sDate > DATEADD(yy, -1, getdate())
group by usrID
) as t
inner join users as u on t.usrID = u.usrID
order by t.cnt desc
Here's what I have so far:
var topUser = (from p in _context.Sessions
where p.SDate > DateTime.Now.AddYears(-1)
join c in _context.Users on p.UsrId equals c.UsrId into j1
from j2 in j1.DefaultIfEmpty()
// group j2 by p.UsrId into grouped
select new
{
p.UsrId,
j2.FirstName,
j2.LastName,
cnt = p.RId
})
//.OrderBy(d => d.cnt)
//.GroupBy(o => o.UsrId)
.Take(5);
I'm having trouble figuring out how to include count() and group by clauses. When I include groupBy my other columns disappear. Thank you.
This is the answer to your answer - not to your original query. I would put it as comment, but without formatting it's hard to explain
Assuming User object has collection of Session your first statement can be drastically simplified:
var topUsers = _context.Sessions
.Where(s => s.SDate > DateTime.Now.AddYears(-1))
.Select(s => new
{
s.UsrId,
cnt = s.User.Sessions.Count(u => u.UsrId == s.UsrId)
})
.OrderByDescending(s => s.cnt)
.Take(5);
You can shape the results to get a ViewModel that also has FirstName and LastName. It all boils down to defining a model with one-to-many relationship
var topUser = (from p in _context.Sessions
where p.SDate > DateTime.Now.AddYears(-1)
join c in _context.Users on p.UsrId equals c.UsrId into j1
from j2 in j1.DefaultIfEmpty()
group j2 by p.UsrId into g
select new
{
UsrId = g.Key,
FirstName = g.Select(x => x.FirstName).FirstOrDefault(),
LastName = g.Select(x => x.LastName).FirstOrDefault(),
sCount = g.Count()
})
.OrderByDescending(d => d.sCount)
.Take(5);
Alright so it's not the most efficient but it works:
var topUsers = _context.Sessions
.Where(s => s.SDate > DateTime.Now.AddYears(-1))
.GroupBy(s => s.UsrId)
.Select(ws => new { ws.Key, cnt = ws.Count() })
.OrderByDescending(s => s.cnt)
.Take(5);
var topNamedUsers = topUsers.Join(_context.Users, ws => ws.Key, ud => ud.UsrId, (ws, ud) => new { ws.Key, ud.FirstName, ud.LastName, ws.cnt });
Wondering why LINQ doesn't have a Left Join method. I've been trying to figure this out with myriad examples on SO, but no such luck. The other examples show simple examples with one join. If I group the joins then I only get references to the TradeCountries table in the select statement.
Being new to LINQ, I could've had this done 4 hours ago with a simple SELECT statement, but here I'm am trying to figure out why the LeftJoin method was left out of LINQ.
What does the line with "LeftJoin" need to be changed to make this work?
/*
* GetTop5Distributors
#param int array of series IDs
*/
public List<TopDistributors> Get5TopDistributors(IEnumerable<int> seriesIds)
{
_context = new MySQLDatabaseContext();
var result = _context.TradesTrades
.Join(_context.TradesSeries, tt => tt.SeriesId, ts => ts.Id, (tt, ts) => new { tt, ts })
.Join(_context.TradesTradeDistributors, tsd => tsd.tt.Id, ttd => ttd.TradeId,
(tsd, ttd) => new { tsd, ttd })
.Join(_context.TradesOrganisations, tsdto => tsdto.ttd.DistributorId, to => to.Id,
(tsdto, to) => new { tsdto, to })
.LeftJoin(_context.TradesCountries, tsdc => tsdc.to.CountryId, tc => tc.Id,
(tsdc, tc) => new {tsdc, tc})
.Where(x => seriesIds.Contains(x.tsdc.tsdto.tsd.tt.SeriesId))
.Where(x => x.tsdc.tsdto.tsd.tt.FirstPartyId == null)
.Where(x => x.tsdc.tsdto.tsd.tt.Status != "closed")
.Where(x => x.tsdc.tsdto.tsd.tt.Status != "cancelled")
.GroupBy(n => new { n.tsdc.tsdto.tsd.tt.SeriesId, n.tsdc.tsdto.ttd.DistributorId })
.Select(g =>
new TopDistributors
{
SeriesId = g.Key.SeriesId,
DistributorName = g.Select(i => i.tsdc.to.Name).Distinct().First(),
IsinNickname = g.Select(i => i.tsdc.tsdto.tsd.ts.Nickname).Distinct().First(),
CountryName = g.Select(i => i.tc.Name).Distinct().First(),
CommissionTotal = Math.Ceiling(g.Sum(i => i.tsdc.tsdto.ttd.Commission))
}
)
.OrderByDescending(x => x.CommissionTotal)
.Take(5)
.ToList();
return result;
}
Here's the rather simple select statement that is taking orders or magnitude too long to convert to LINQ.
SELECT
trades_trades.series_id,
trades_organisations.`name`,
trades_series.nickname,
trades_countries.name as Country_Name,
SUM(trades_trade_distributors.commission) as Commission_Total
FROM
trades_trades
JOIN trades_series
ON trades_series.id = trades_trades.series_id
JOIN trades_trade_distributors
ON trades_trades.id = trades_trade_distributors.trade_id
JOIN trades_organisations
ON trades_trade_distributors.distributor_id = trades_organisations.id
LEFT JOIN trades_countries
ON trades_organisations.country_id = trades_countries.id
WHERE trades_trades.series_id IN (
17,
18)
AND trades_trades.first_party_id IS NULL
AND trades_trades.status <> 'closed'
AND trades_trades.status <> 'cancelled'
GROUP BY trades_trades.series_id, trades_trade_distributors.distributor_id
ORDER BY Commission_Total DESC
Following my recipe, here is a more or less straightforward translation of the SQL to LINQ. I moved the where to be near what it constrains, and used let to create a convenient name for the Sum, as LINQ doesn't allow you to forward reference anonymous object members.
var ans = from tt in trades_trades
where new[] { 17, 18 }.Contains(tt.series_id) && tt.first_party_id == null &&
tt.status != "closed" && tt.status != "cancelled"
join ts in trades_series on tt.series_id equals ts.id
join ttd in trades_trade_distributors on tt.id equals ttd.trade_id
join to in trades_orginizations on ttd.distributor_id equals to.id
join tc in trades_countries on to.country_id equals tc.id into tcj
from tc in tcj.DefaultIfEmpty() // GroupJoin -> left join
group new { tt, ts, ttd, to, tc } by new { tt.series_id, ttd.distributor_id } into tradeg
let Commission_Total = tradeg.Sum(trade => trade.ttd.commission)
orderby Commission_Total descending
select new {
tradeg.Key.series_id,
tradeg.First().to.name,
tradeg.First().ts.nickname,
Country_Name = tradeg.First().tc == null ? null : tradeg.First().tc.name,
Commission_Total
};
This is my first post and I hope you can help me. I didn't find an answer so here I'm:
I created this query in SQL and it works.
string consultaSQL =
#"SELECT a.GastosEstudio - ISNULL(SUM(b.GastosEstudioR),0) AS restagastos, a.Articulo - ISNULL(SUM(b.ArticuloR),0) AS restaarticulo, a.Honorarios - ISNULL(SUM(b.HonorariosR),0) AS restahonorarios, a.IVAHonorarios - ISNULL(SUM(b.IVAHonorariosR),0) AS restaivahonorarios FROM deudores a LEFT JOIN recibos b ON a.DNI=b.DNI WHERE a.DNI = #DNI GROUP BY a.GastosEstudio, a.Articulo, a.Honorarios, a.IVAHonorarios";
Now I need to do the same but in LINQ. Basically: I have two tables (deudores and recibos). In deudores I have the debt with the different concepts (columns):
gastos, articulo, honorarios, ivahonorarios
In the table recibos I insert the receipts with the same columns.
The SQL query sums the receipts and subtracts the debt. The closest I get in LINQ was this:
var query = (from d in bd.deudores
join r in bd.recibos on d.DNI equals r.DNI
where d.DNI == DNI
group d by d.DNI into g
select new
{
DNI = g.Key,
articulo = g.Max(x => x.Articulo) - g.Sum(x => x.ArticuloR),
gastos = g.Max(x => x.GastosEstudio) - g.Sum(x => x.GastosEstudioR),
honorarios = g.Max(x => x.Honorarios) - g.Sum(x => x.HonorariosR),
ivah = g.Max(x => x.IVAHonorarios) - g.Sum(x => x.IVAHonorariosR),
});
The problem with this query is that if there is no receipt does not show any information (should show the initial debt)
I try with DefaultIfEmpty but didn't work:
var query = (from d in bd.deudores
join r in bd.recibos on d.DNI equals r.DNI into Pagos
from p in Pagos.DefaultIfEmpty()
where d.DNI == DNI
group d by d.DNI into g
select new
{
DNI = g.Key,
articulo = g.Max(x => x.Articulo) - g.SelectMany(x => x.recibos).Count() >= 1
? g.SelectMany(x => x.recibos).Sum(y => y.ArticuloR)
: 0,
gastos = g.Max(x => x.GastosEstudio) - g.SelectMany(x => x.recibos).Count() >= 1
? g.SelectMany(x => x.recibos).Sum(y => y.GastosEstudioR)
: 0,
honorarios = g.Max(x => x.Honorarios) - g.SelectMany(x => x.recibos).Count() >= 1
? g.SelectMany(x => x.recibos).Sum(y => y.HonorariosR)
: 0,
ivah = g.Max(x => x.IVAHonorarios) - g.SelectMany(x => x.recibos).Count() >= 1
? g.SelectMany(x => x.recibos).Sum(y => y.IVAHonorariosR)
: 0
});
The problem with this query is that it does not subtract it.
Any suggestion?
Thank you!
You want the equivalent of an outer join, so you correctly turn to a GroupJoin, or join ... into. But the query part ...
from d in bd.deudores
join r in bd.recibos on d.DNI equals r.DNI into Pagos
from p in Pagos.DefaultIfEmpty()
where d.DNI == DNI
group d by d.DNI into g
... does more than you want. In fluent LINQ syntax its structure is equivalent to
bd.deudores.GroupJoin(bd.recibos, ...)
.SelectMany(...)
.GroupBy(...)
The point is that the first GroupJoin creates a collection of deudores, each having a group of their recibos, that may be empty. Then the SelectMany flattens it into pairs of one deudores and one recibos or null. Subsequently, the GroupBy creates groups with null elements.
The first GroupJoin is all you need:
from d in bd.deudores
join r in bd.recibos on d.DNI equals r.DNI into g
select new
{
DNI = d.DNI,
articulo = d.Articulo - g.Select(x => x.ArticuloR).DefaultIfEmpty().Sum(),
gastos = d.GastosEstudio - g.Select(x => x.GastosEstudioR).DefaultIfEmpty().Sum(),
honorarios = d.Honorarios - g.Select(x => x.HonorariosR).DefaultIfEmpty().Sum(),
ivah = d.IVAHonorarios - g.Select(x => x.IVAHonorariosR).DefaultIfEmpty().Sum()
});
By adding DefaultIfEmpty() it is ensured that Sum will return 0 when there are no elements.
#Gert Arnold: The relationship between the two tables is a column name DNI. In the table deudores is PK and in the table recibos is FK. Last night i tried this code and it works:
var query = (from d in bd.deudores
join r in bd.recibos
on d.DNI equals r.DNI into g
where d.DNI == DNI
select new
{
articulo = d.Articulo - g.Sum(x => x.ArticuloR) ?? d.Articulo,
gastos = d.GastosEstudio - g.Sum(x => x.GastosEstudioR) ?? d.GastosEstudio,
honorarios = d.Honorarios - g.Sum(x => x.HonorariosR) ?? d.Honorarios,
ivah = d.IVAHonorarios - g.Sum(x => x.IVAHonorariosR) ?? d.IVAHonorarios
});
Is it the best way to do it ?. If you want to give me your opinion will be welcome.
Regards!
I need help producing the required C# code to implement the following SQL query. I am unsure if this is even possible?
select p.Name, r.Id, r.Status, r.Created, r.DepartmentId
from (select r.*, row_number() over (partition by personid order by created desc) as seqnum
from checkin r
where r.departmentid = '7AF20674-AEC1-4D4C-B1EA-88B1D7E8F3DB' and cast(created as date) = '2013-02-11'
) r join
person p
on r.personid = p.id
where seqnum = 1
order by p.name desc
Before i used to only have one registration per day per person, so the following was possible. Now i can have several registrations per person per day, thats why SQL has been updated.
var query = from b in context.Persons
join c in context.CheckIns
on b.Id equals c.PersonId into JoinedPersCheck
from c in JoinedPersCheck.Where(i => i.Date.Equals(date)).DefaultIfEmpty()
where b.DepartmentId.Equals(departmentId)
orderby b.Name
select new Model.PersonCheckIn
{
CheckIn = MapToCheckInModel(c),
Person = MapToModel(b),
};
return query;
Try this:
var query = context.CheckIns
.Where(p => p.DepartmentId == departmentId && p.Created.Date == date)
.GroupBy(r => r.PersonId)
.Select(g => g.OrderByDescending(p => p.Created).First())
.Join(context.Persons, c => c.PersonId, p => p.Id,
(c,p) => new { p.Name, c.Id, c.Status, c.Created, c.DepartmentId})
.OrderByDescending(f => f.Name);
I decided to try my hand at LINQ and so far its been a miserable failure. I need to convert the following SQL query to LINQ:
SELECT
MAX(A.NEXTPAYMENTDATE) as NextPaymentDate
, SUM(B.PurchasePrice) - SUM(A.Amount) AS BALANCE
, c.FirstName
, c.LastName
, b.[year]
, b.make
, b.model
FROM Payments A
JOIN Vehicles B ON A.VehicleId = B.Id
JOIN Customers C ON b.CustomerId = c.Id
GROUP BY VehicleId, c.FirstName, c.LastName, b.[year], b.make, b.model
HAVING SUM(B.PurchasePrice) - SUM(A.Amount) > 0
This is what I have so far. It seems to work to a certain extent, but I don't know how to progress from here.
var groupedpayments =
from payments in db.Payments
group payments by new { payments.VehicleId }
into paymentGroup
let maxDate = paymentGroup.Max(x => x.NextPaymentDate)
let paid = paymentGroup.Sum(x => x.Amount)
select
new { Payments = paymentGroup.Where(x => x.NextPaymentDate == maxDate)};
I think that is what you need.
var query =
Payments.Join(Vehicles, p => p.VehicleId, v => v.Id, (p, v) => new {p, v})
.Join(Customers, d => d.v.CustomerId, c => c.Id, (d, c) => new {d, c})
.GroupBy(r =>
new {
r.d.p.VehicleId,
r.d.v.year,
r.d.v.make,
r.d.v.model,
r.c.FirstName,
r.c.LastName
},
(g, data) =>
new {
FirstName = g.FirstName,
LastName = g.LastName,
Year = g.year,
Make = g.make,
Model = g.model,
NextPaymentDate = data.Max(dd => dd.d.p.NEXTPAYMENTDATE),
Balance = data.Sum(dd => dd.d.v.PurchasePrice)
- data.Sum(dd => dd.d.p.Amount)})
.Where(r => r.Balance > 0);