How can I write this query in linq? - sql

I know there are probably a ton of questions like this already but i'm having trouble
select *
from [Group]
where GroupId not in
(select GroupId
from CustomerGroup
where CustomerId = 189621)
i have myGroups = db.Groups.Where(e=> e.GroupId), but how do i say not in?
i am kind of there
var myGroups = from a in db.Groups
where!(from b in db.CustomerGroups
where b.CustomerId == customer.CustomerId )

var groupIds = from cg in db.CustomerGroups
where cg.CustomerId == 189621
select cg.GroupId;
var myGroups = from g in db.Groups
where !groupIds.Contains(g.GroupId)
select g;
Need a list to disqualify first. NOT IN is basically a !(IEnumerable).Contains() in LINQ (since you're comparing to a set).

Using lambda expression, you probably can do it like this
var groupIds = db.CustomerGroups.Where(x => x.CustomerId == 189621).Select(x => x.GroupId);
var myGroups = db.CustomerGroups.Where(x => !groupIds.Contains(x.GroupId)).ToList();

Related

Linq to SQL - Query with multiple joins, sum, grouping, having

I have the following query that I would like to translate to linq.
SELECT
SUM(Credits.CreditAmount)
,Transactions.Id
,Person.FullName
,Person.Id
FROM
Person
JOIN
Transactions
ON Person.AccountId = Transactions.AccountId
JOIN Credits
ON Transactions.Id = Credits.TransactionId
WHERE
Person.Type = 'AccountHolder'
AND Person.Status = 'Active'
AND Transactions.CancelledDate IS NULL
AND Credits.CancelledDate IS NULL
GROUP BY Transactions.AccountId, Person.FullName, Person.Id
HAVING SUM(Credits.CreditAmount) > 20
This is what I came up with. It's an absolute pig... The SQL it generates must be awful.
var query = from p in Person
join t in Transactions
on p.AccountId equalas t.AccountId
join c in Credits
on t.TransactionId = c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
group new { c.CreditAmount, t.AccountId, p.FullName, p.Id } by new { t.AccountId, p.FullName, p.SSN } into grp
let sumC = grp.Select(x => x.CreditAmount).Sum()
select new
{
TotalCredit = sumC,
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
query.Where(p => p.TotalServiceCredit > 20);
The SQL query runs in approximately 3 seconds but I have yet to find the patience to let the Linq query finish. I was wondering if there is something different I should be doing to accomplish this "group, sum, having" query I'm trying to write? Is there something I can do to help Linq generate more performat SQL?
UPDATE
Turns out sgmoore had the right idea. The key to the performance issue was in his answer.
The difference between this
let sumC = grp.Select(x => x.CreditAmount).Sum()
and this
TotalCredit = grp.Sum(x => x.CreditAmount)
was the difference between a query that finishes and one that does not.
See my revised LINQ query below which completes in about the same time as the SQL (5.3 seconds for SQL vs 5.6 seconds for LINQ).
var query = from p in Person
join t in Transactions
on p.AccountId equalas t.AccountId
join c in Credits
on t.TransactionId = c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
group new { c.CreditAmount, t.AccountId, p.FullName, p.Id } by new { t.AccountId, p.FullName, p.SSN } into grp
select new
{
TotalCredit = grp.Sum(x => x.CreditAmount),
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
query.Where(p => p.TotalServiceCredit > 20);
Thanks for all your help!
I don't disagree with WEI_DBA's comment but if you need to do this, then you might find it easier to break this into several queries, eg
var query1 = from p in Person
join t in Transactions on p.AccountId equals t.AccountId
join c in Credits on t.TransactionId equals c.TransactionId
where p.Status == "Active" &&
p.Type = "AccountHolder" &&
t.CancelledDate == null &&
c.CancelledDate == null
select new { c.CreditAmount, t.AccountID, p.FullName, p.Id};
var query2 = (from p in query1
group p by new { p.AccountId, p.FullName, p.Id } into grp
select new
{
TotalCredit = grp.Sum(x => x.CreditAmount),
AccountId = grp.Key.AccountId,
FullName = grp.Key.FullName,
Id = grp.Key.Id
};
var query3 = (from p in query2 where p.TotalCredit > 20 select p);
Then you can let LINQ combine this into one sql command.
As always, it is a good idea to check and verify the actual TSQL generated.

SQL Query to LINQ Lambda expression

I am trying to convert a bit of SQL containing a LEFT OUTER JOIN with a GROUP BY clause into a LINQ Lambda expression.
The SQL I need to convert is:-
SELECT m.MemberExternalPK
FROM Member.Member AS m LEFT OUTER JOIN Member.Account AS a ON m.MemberID = a.MemberID
GROUP BY MemberExternalPK
HAVING COUNT(AccountID) = 0
I have managed to get it working correctly with an INNER JOIN between Member and Accounts like this (for a count of Account = 1) but this does not work for Accounts with a count of 0 (hence the LEFT OUTER JOIN is required):-
Members.Join(Accounts, m => m.MemberID, a => a.MemberID, (m, a) => new {m, a})
.GroupBy(t => t.m.MemberExternalPK, t => t.a)
.Where(grp => grp.Count(p => p.AccountID != null) == 1)
.Select(grp => grp.Key)
I have been trying to experiment with the .DefaultIfEmpty() keyword but have so far been unsuccessful. Any help would be greatly appreciated :)
I think this is what you're after:
Query syntax
var members = new List<Member>
{
new Member {MemberId = 1, MemberExternalPk = 100},
new Member {MemberId = 2, MemberExternalPk = 200}
};
var accounts = new List<Account>
{
new Account {AccountId = 1, MemberId = 1}
};
var query =
from m in members
join a in accounts on m.MemberId equals a.MemberId into ma
from ma2 in ma.DefaultIfEmpty()
where ma2 == null
group ma2 by m.MemberExternalPk into grouped
select new {grouped.Key};
The result of this example is that only the number 200 is returned. As it will only return the MemberExternalPk for members that don't have an account. i.e. As MemberId 2 doesn't have a related Account object, it is not included in the reuslts.
var list = members.GroupJoin(accounts,m=>m.MemberId, a => a.MemberId,
(m,a) => new {m,a})
.Where(x=>x.a.Count()==0)
.Select(s=>s.m.MemberExternalPk);

Subquery with linq

I want to do a subquery with linq but it doesn't work. :-( I've searched google for an answer, but I don't know how to solve the problem.
This is my sql
string strSQL = #"SELECT a.ident, a.ben1
FROM pwdata a
WHERE a.iid = (SELECT max(b.iid) FROM pwdata b WHERE b.ident = a.ident)";
That's how I tried to do with Linq, but this is not the right way
var query = from i in maxxContext.pwdata
where i.IID = (SELECT max(b.iid) FROM pwdata b WHERE b.ident = a.ident)
orderby i.ident
select new CompareParts
{
PartNumber = i.ident,
PartName = i.ben1
};
return query.ToList().Distinct();
Can anyone of you help me?
It's not clear why you've started intermingling LINQ with regular SQL. It doesn't work like that.
This should work though:
var query = from i in maxxContext.pwdata
where i.IID == (pwdata.Where(b => b.ident == i.ident)
.Max(b => b.iid))
orderby i.ident
select new CompareParts
{
PartNumber = i.ident,
PartName = i.ben1
};
Alternatively, you could do a join:
var query = from i in maxxContext.pwdata
join b in pwdata on i.ident equals b.ident into bs
where i.IID == bs.Max(b => b.iid)
orderby i.ident
select new CompareParts
{
PartNumber = i.ident,
PartName = i.ben1
};

I need help re-writing a SQL query into LINQ format

I'm not good with LINQ yet and could use some help with the syntax.
Thanks!
The below query needs to be written in LINQ for C#.
SELECT Galleries.GalleryTitle, Media.*
FROM Galleries
INNER JOIN Media ON Galleries.GalleryID = Media.GalleryID
WHERE (Galleries.GalleryID = 150)
ORDER BY MediaDate DESC, MediaID DESC
Or with query syntax:
var query = from g in db.Galleries
join m in db.Media on g.GalleryID equals m.GalleryID
where g.GalleryID == 150
orderby m.MediaDate descending, m.MediaID descending
select new { g.GalleryTitle, Media = m };
Something like this:
var query = db.Galleries
.Join(db.Media, g => g.GalleryID, m => m.GalleryID, (g, m) => new {g, m})
.Where(r.g.GalleryID == 150)
.Select(res => new {res.g.GalleryTitle, Media = res.m}
.OrderByDescending(o => o.Media.MediaDate)
.ThenByDescending(o => o.Media.MediaID);

Help with LINQ join

var q = (from Labels in dc.tblArtworkDataLabels select Labels).ToList();
But I need this to do the quivalent of:
SELECT d.ID, d.labelID, d.dataID, d.data, l.templateID
FROM tblArtworkDataLabels AS d INNER JOIN
tblArtworkData AS l ON d.dataID = l.ID
WHERE (l.templateID = 238)
How do I do this in LINQ?
Edit
Sorry! Missed the WHERE clause on original statmenet!
var result = dc.tblArtworkDataLabels
.Join(dc.tblArtworkData, l => l.ID, d => d.dataID, (l, d) => new {l, d})
.Select(o => new {
Id = o.d.ID,
LabelId = o.d.labelID,
DataId = o.d.dataID,
Data = o.d.data,
TemplateId = o.l.templateID,
})
.Where(o => o.l.templateID == 238);
If you have a correct foreign key on tblArtworkData to the primary key on the tblArtworkDataLabels and have imported them correctly into the DBML designer you can have LINQ2SQL implicitly creating the join:
from l in tblArtworkData
where l.templateID = 238
select new {
Id = l.tblArtworkDataLabel.ID,
LabelId = l.tblArtworkDataLabel.labelID,
DataId = l.tblArtworkDataLabel.dataID,
Data = l.tblArtworkDataLabel.data,
TemplateId = l.templateID,
}
See my answer on the question "LINQ to SQL: Multiple joins ON multiple Columns. Is this possible?" for how the implicit join translates to SQL.
Edit:
In the case I misunderstood your relations and you have many tblArtworkDataLabels to one tblArtworkData you have to turn the query the other way around
from d in tblArtworkDataLabels
where d.tblArtworkData.templateID = 238
select new {
Id = d.ID,
LabelId = d.labelID,
DataId = d.dataID,
Data = d.data,
TemplateId = d.tblArtworkData.templateID,
}
try
var q = (from Labels in dc.tblArtworkDataLabels
join data in dc.tblArtworkData on Labels.ID equals data.DataID select Labels).ToList();