How to write subquery with the any quantifier using linq? - c#

I have a problem with using any in linq I do not know how to do it correctly.
I have to write this in linq:
SELECT ename, job, deptno
FROM emp
WHERE sal > ANY
(
SELECT DISTINCT sal
FROM emp
WHERE deptno = 30
);
I write only this:
var min = (from emp in Emps
where emp.Deptno == 30
select emp.Sal
).Distinct();
var result = (from emp in Emps
where min.Any() > emp.Sal
select new
{
emp.Ename
});

Linq doesn't have an any/some operator in the way Sql Server does.
var salariesInTargetDepartment = Emps
.Where(x => x.Deptno == 30)
.Select(x => x.Sal)
.Distinct()
.ToList(); // the ToList is not required, but seeing you're going to be executing
// against this query many times, it will be better to cache the results.
var matchingEmployees = Emps
.Where(emp => salariesInTargetDepartment
.Any(target => emp.Sal > target)
);
The where clause in the second statement says "Only include this record if this record's Sal property is greater than at least one entry in the salariesInTargetDepartment collection."

Related

Linq Query Group By Multiple Columns Having Count > 1

I have a query I know how to do in SQL but struggling to figure out the LINQ query. Here is the SQL.
SELECT ordNo, tranNo, COUNT(distinct custNo)
FROM orders
GROUP BY ordNo, tranNo
HAVING COUNT(distinct custNo) > 1
I don't feel like this is the same question that I see you marked as a duplicate. The linked question only groups on a single property. I've lost track of the Linq queries I've tried but here is one.
var countList = from o in orders
group o by new {o.orderNo, o.tranNo, o.custNo}
into grp
where grp.Key.custNo.Distinct().Count() > 1
select grp;
I tried the suggestion below but like someone commented you can't access the custNo property.
Just spitballing since I don't know the table structure.
context.orders
.GroupBy(o => new { o.ordNo, o.tranNo, o.custNo })
.Where(o => o.custNo.Distinct().Count() > 1)
.Select(o => new {
ordNo = o.ordNo,
tranNo = o.tranNo
});

Changing a SQL query to a linq query - syntax

I'm having problem coding my linq query.
This is my SQL query:
select
price, (cast(sum(Quantity) as decimal(7,2)))
from
OrderDetails
where
ItemID = 1000
group by
price
order by
price
This is my linq query:
var result = from od in db.OrderDetails
where od.ItemID == 1000
orderby od.Price
group by price
select od.price, (cast(sum(od.Quantity) as decimal(7, 2)));
This linq query seems to be incorrect. What is the right syntax?
This should work:
(You need to move the order part to be after the grouping)
var q = (from o in context.OrderDetails
where o.ItemID == 1000
group o by o.price into grp
select new
{
Price = grp.Key,
Quantity = grp.Sum(x => x.Quantity)
}).OrderBy(a => a.Price);

left join in Linq query

I'm trying to do a left join, not an inner join in a linq query. I have found answers related to using DefaultIfEmpty() however I can't seem to make it work. The following is the linq query:
from a in dc.Table1
join e in dc.Table2 on a.Table1_id equals e.Table2_id
where a.Table1_id == id
orderby a.sort descending
group e by new
{
a.Field1,
a.Field2
} into ga
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects = (from g in ga select new SubObject{
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
The query only gives me the rows from table 1 that have a corresponding record in table 2. I would like every record in table 1 populated into MyObject and a list of 0-n corresponding records listed in manySubObjects for each MyObject.
UPDATE:
I tried the answer to the question that is a "possible duplicate", mentioned below. I now have the following code that does give me one record for each item in Table1 even if there is no Table2 record.
from a in dc.Table1
join e in dc.Table2 on a.Table1_id equals e.Table2_id into j1
from j2 in j1.DefaultIfEmpty()
where a.Table1_id == id
orderby a.sort descending
group j2 by new
{
a.Field1,
a.Field2
} into ga
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects = (from g in ga select new SubObject{
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
However, with this code, when there is no record in table2 I get "manySubObject" as a list with one "SubObject" in it with all null values for the properties of "SubObject". What I really want is "manySubObjects" to be null if there is no values in table2.
In reply to your update, to create the null listing, you can do a ternary in your assignment of manySubObjects.
select new MyObject
{
field1= ga.Key.Field1,
field2= ga.Key.Field2,
manySubObjects =
(from g in ga select g).FirstOrDefaut() == null ? null :
(from g in ga select new SubObject {
fielda= g.fielda,
fieldb= g.fieldb
}).ToList()
}).ToList();
Here is a dotnetfiddle that tries to do what you're attempting. https://dotnetfiddle.net/kGJVjE
Here is a subsequent dotnetfiddle based on your comments. https://dotnetfiddle.net/h2xd9O
In reply to your comments, the above works with Linq to Objects but NOT with Linq to SQL. Linq to SQL will complain that it, "Could not translate expression ... into SQL and could not treat as a local expression." That's because Linq cannot translate the custom new SubObject constructor into SQL. To do that, you have to write more code to support translation into SQL. See Custom Method in LINQ to SQL query and this article.
I think we've sufficiently answered your original question about left joins. Consider asking a new question about using custom methods/constructors in Linq to SQL queries.
I think the desired Result that you want can be given by using GroupJoin()
The code Below will produce a structure like so
Field1, Field2, List < SubObject > null if empty
Sample code
var query = dc.Table1.Where(x => Table1_id == id).OrderBy(x => x.sort)
.GroupJoin(dc.Table2, (table1 => table1.Table1_id), (table2 => table2.Table2_id),
(table1, table2) => new MyObject
{
field1 = table1.Field1,
field2 = table1.Field2,
manySubObjects = (table2.Count() > 0)
? (from t in table2 select new SubObject { fielda = t.fielda, fieldb = t.fieldb}).ToList()
: null
}).ToList();
Dotnetfiddle link
UPDATE
From your comment I saw this
ga.Select(g = > new SubObject(){fielda = g.fielda, fieldb = g.fieldb})
I think it should be (depends on how "ga" is built)
ga.Select(g => new SubObject {fielda = g.fielda, fieldb = g.fieldb})
Please update your question with the whole query, it will help solve the issue.
** UPDATE BIS **
sentEmails = //ga.Count() < 1 ? null :
//(from g in ga select g).FirstOrDefault() == null ? null :
(from g in ga select new Email{
email_to = g.email_to,
email_from = g.email_from,
email_cc = g.email_cc,
email_bcc = g.email_bcc,
email_subject = g.email_subject,
email_body = g.email_body }).ToList()
Should be:
sentEmails = //ga.Count() < 1 ? null :
((from g in ga select g).FirstOrDefault() == null) ? null :
(from g in ga select new Email{
email_to = g.email_to,
email_from = g.email_from,
email_cc = g.email_cc,
email_bcc = g.email_bcc,
email_subject = g.email_subject,
email_body = g.email_body }).ToList()
Checks if the group has a First, if it doesn't the group doesn't have any records so the Action.Name for a Time Stamp has no emails to send. If the First isn't null the loop throw the group elements and create a list of Email,
var results =
(
// Use from, from like so for the left join:
from a in dc.Table1
from e in dc.Table2
// Join condition goes here
.Where(a.Id == e.Id)
// This is for the left join
.DefaultIfEmpty()
// Non-join conditions here
where a.Id == id
// Then group
group by new
{
a.Field1,
a.Field2
}
).Select(g =>
// Sort items within groups
g.OrderBy(item => item.sortField)
// Project required data only from each item
.Select(item => new
{
item.FieldA,
item.FieldB
}))
// Bring into memory
.ToList();
Then project in-memory to your non-EF-model type.

How can I convert this SQL Query into LINQ (OVER (PARTITION BY Date))

Here's the query I'm trying to convert into Linq:
SELECT R.Code,
R.FlightNumber,
S.[Date],
S.Station,
R.Liters,
SUM(R.Liters) OVER (PARTITION BY Year([Date]), Month([Date]), Day([Date])) AS Total_Liters
FROM S INNER JOIN
R ON S.ID = R.SID
WHERE (R.Code = 'AC')
AND FlightNumber = '124'
GROUP BY Station, Code, FlightNumber, [Date], Liter
ORDER BY R.FlightNumber, [Date]
Thanks for any help.
UPDATE: Here is the Linq code I'm trying it on; I cannot make the OVER PARTITION by Date.
var test =
(from record in ent.Records join ship in ent.Ship on record.ShipID equals ship.ID
orderby ship.Station
where ship.Date > model.StartView && ship.Date < model.EndView && ship.Station == model.Station && record.FlightNumber == model.FlightNumber
group record by new {ship.Station, record.Code, record.FlightNumber, ship.Date, record.AmountType1} into g
select new { g.Key.Station, g.Key.Code, g.Key.FlightNumber, g.Key.Date, AmmountType1Sum = g.Sum(record => record.AmountType1) });
Execute query first without aggregation:
var test =
(from record in ent.Records join ship in ent.Ship on record.ShipID equals ship.ID
orderby ship.Station
where ship.Date > model.StartView && ship.Date < model.EndView && ship.Station == model.Station && record.FlightNumber == model.FlightNumber
select new {ship.Station, record.Code, record.FlightNumber, ship.Date, record.AmountType1};
Then calculate sum
var result =
from row in test
select new {row.Station, row.Code, row.FlightNumber, row.Date, row.AmountType1,
AmountType1Sum = test.Where(r => r.Date == row.Date).Sum(r => r.AmountType1) };
This should produce the same effect as database query. Code above may contain errors, because I wrote it only here.
I've answered a similar thread on: LINQ to SQL and a running total on ordered results
On that thread it was like this:
var withRuningTotals = from i in itemList
select i.Date, i.Amount,
Runningtotal = itemList.Where( x=> x.Date == i.Date).
GroupBy(x=> x.Date).
Select(DateGroup=> DateGroup.Sum(x=> x.Amount)).Single();
In you situation, you might have to join the two tables together first while grouping, then run the same concept above on the joined table result.

How to use group by and having count in Linq

I am having trouble trying to convert the following query from SQL to Linq, in particular with the having count and group by parts of the query:
select ProjectID
from ProjectAssociation
where TeamID in ( select TeamID
from [User]
where UserID in (4))
group by ProjectID
having COUNT(TeamID) = (select distinct COUNT(TeamID)
from [User]
where UserID in (4))
Any advice on how to do so would be much appreciated.
var groups = from pa in ProjectAssociation
let teamIds = User.Where(u => u.UserID == 4).Select(u => u.TeamID)
where teamIds.Contains(pa.TeamID)
group pa by pa.ProjectID;
var result = from g in groups
let count = User.Where(u => u.UserID == 4).Select(u => u.TeamID).Distinct().Count()
where g.Count() == count
select g.Key;
Or maybe more optimal:
var teamIds = User.Where(u => u.UserID == 4).Select(u => u.TeamID).AsEnumerable();
var groups = ProjectAssociation.Where(pa => teamIds.Contains(pa.TeamID)
.GroupBy(pa => pa.ProjectID);
var result = from g in groups
let count = teamIds.Distinct().Count()
where g.Count() == count
select g.Key;
By the way, i think that by
select distinct COUNT(TeamID)
you meant:
select COUNT(distinct TeamID)
There is a tool (cheap) that will convert queries like this for you. It's called Linqer. I own a copy and have found that it's able to convert event the most complex of queries. The URL is http://www.sqltolinq.com/
It's not free, but it's pretty inexpensive and has a 30 day trial.

Categories