I have a query that I wrote in SQL, which works, and I am trying to move this to the appropriate LINQ statement, and can't seem to get it quite right.
The SQL query:
select sku
from Table
group by sku
having count(sku) > 1 and count(distinct(unit)) > 1
and what I have so far with LINQ
var dupCount = (from val in dt.AsEnumerable()
group val by new {sku = val[4]} into grp
where grp.Count() > 1 && grp.unit.Distinct().Count() > 1
select grp).ToList();
I cant seem to figure out how to tell the where within the group to only pull the records with a distinct "unitreserve".
I cant seem to figure out how to tell the where within the group to only pull the records with a distinct "unitreserve".
Select the "unitreverse" field, apply Distinct and then Count it:
where grp.Count() > 1 &&
grp.Select(dr => dr["unitreserve"]).Distinct().Count() > 1
Related
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
});
I am trying to return all distinct rows from Staging below where Staging.CenterCode does not exist in Centers.CenterCode.
At the moment Stagings has around 850 distinct CenterCodes and Centers is empty so I should be getting all of the distinct rows, but count begs to differ :)
Any ideas?
var query =
(from s in db.Stagings
join t in db.Centers on s.CenterCode equals t.CenterCode into tj
from t in tj.DefaultIfEmpty()
where s.CenterCode != t.CenterCode
select s.CenterCode).Distinct();
var c = query.Count();
I only need the unique columns from staging so not sure if I actually need a join with the above as I am not ever using data returned from Centers - I have however tried both and get the same 0 value for count.
Any ideas?
I would not use a join, but use a Contains.
var centerCodesQuery = db.Centers.CenterCode
.Select(x => x.CenterCode);
var query = db.Staging
.Where(x => !centerCodesQuery.Contains(x.CenterCode))
.Select(x => x.CenterCode)
.Distinct();
var c = query.Count();
the join is an inner join. So, if none of the rows in 1 table match the other table on the specified identifier then it will return 0. In yours you are trying to join 1 table with 850 distinct rows with an empty table. This will return 0.
If you actually want to return only those rows in 1 table that aren't in another you can use Except:
var query = (from s in db.Stagings
select s.CenterCode)
.Except(from t in db.Centers
select t.CenterCode);
var c = query.Count();
Looks like you are trying to implement antijoin via left outer join, which is one of the possible ways, but in order to make it work, you need to change
where s.CenterCode != t.CenterCode
to
where t == null
results = (from r in results
where r.Buildings.Any(x=>x.StructuralElements.Any(s=>s.VALUE == Model.Bedrooms.ToString() && s.CATEGORY=="RM"))
select r);
I think I'm missing joins here. But maybe they are implied? The execution runs so long I can't do a watch to evaluate the generated query expression
The biggest problem in this query is this:
--#p1 = Models.Bedrooms.ToString()
--#p2 = "RM"
SELECT * FROM Results r WHERE EXISTS
(SELECT x.* FROM Results tr JOIN Buildings x ON tr.SomeID=x.SomeID WHERE tr.ID = r.ID AND EXISTS
(SELECT s.* FROM StructuralElements s JOIN Buildings tx ON tx.OtherID = s.OtherID WHERE tx.ID=x.ID AND s.VALUE = #p1 AND s.Category = #p2))
Do you see why this would be bad? For every Result, you're running a subquery (which in itself is running a subquery). This is going to be an exponential increase in time/processing as you start adding things at the root levels (Results and Buildings) because of these nested subqueries. Your best bet is to use joins and get distinct r values after you're done. The SQL would like like this:
SELECT DISTINCT
r.*
FROM
Results r
INNER JOIN Buildings x ON x.SomeID = r.SomeID
INNER JOIN StructuralElements s ON s.OtherID = r.OtherID
WHERE
s.VALUE = #p1 AND s.CATEGORY = #p2
The reason this will work is that when you join, if there are more than one to join back, it will duplicate the original row. The following illustration shows
IDs
R X S
1 - -
Join X
1 1 -
1 2 -
1 3 -
Join S
1 1 1
1 1 2
1 2 5
1 2 6
Assuming S=2 and S=6 meet your criteria, then it will return (in R,X,S form) rows 1,1,2 and 1,2,6. Getting just the distinct r in this case will only return R=1, which is what you're trying to accomplish. Using EF, the relationships already exist, so you don't need to do anything extra, just reference the columns you're trying to filter by:
results = (from r in results
from x in r.Buildings
from s in x.StructuralElements
where s.VALUE == Model.Bedrooms.ToString() && s.CATEGORY=="RM"
select r).Distinct();
This is the SelectMany operator at play (which takes a collection and flattens out subcollections into a single collection).
I have this code which queries a database
var buildInfoList = (from m in context.BuildInfoes
where m.ManagerInfoGuid == managerGuid
select m).Take(3).ToList();
the code above gives me the first 3 results, how can i change it to take the last 3?
meaning if i have 100 rows in the database, i want to get 98, 99, 100 and not 1, 2, 3
Reverse the order of the query. The basic idea is reverse the order of the entire query, fetch the first three elements, then reverse the order again to put them back in the right order:
var query = from m in context.BuildInfoes
where m.ManagerInfoGuid == managerGuid
select m;
var lastItems = query.OrderByDescending(x => x.ID).Take(3).Reverse().ToList();
PS: If you were using Linq to Objects (but I guess you aren't) you could use TakeLast from morelinq.
Your are not introducing any order here, so you currently get any 3 results which by chance don't happen to be the ones you want. Establish an order:
var buildInfoList = (from m in context.BuildInfoes
where m.ManagerInfoGuid == managerGuid
orderby m.Name descending
select m).Take(3).ToList();
Using orderby you can specify ascending or descending to reverse the order, which will result in returning the first or last 3 elements using Take.
You can use orderby
var buildInfoList = (from m in context.BuildInfoes
where m.ManagerInfoGuid == managerGuid
orderby m.Id descending
select m).Take(3).ToList();
Or, as #MarkByers said, just use Reverse
var buildInfoList = from m in context.BuildInfoes
where m.ManagerInfoGuid == managerGuid
select m;
var count = buildInfoList.Count();
var list = buildInfoList.Skip(count < 3 ? count - 3 : 0).Take(3).ToList();
edit: Why is this solution different than the others? But this doesn't mean is the best one.
First the OP states that the query is over a database and since the query uses Take without specifying the order, I guess is about Linq To Sql.
This solution is not actually the best because it does two queries, one for the count and the other for to get the items. This solution uses only the SQL to get the last 3 items and doesn't do an order over objects.
While testing it with LINQ Pad I noticed that, when no order is specified, LINQ to SQL generates the order over all the columns
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[id], [t0].[A], [t0].[B], [t0].[C])
Obs.:
The Reverse method is not translated, so is good to be called after a ToList() call
I'd like to translate the following SQL statement into a linq query:
select COUNT(*), itemid, globalid, title, preview, previewimage, previewimage_alt, link
from (
select distinct Id, itemid, globalid, title, preview, previewimage, previewimage_alt,
(select top 1 link from LikeCounter where GlobalId=x.GlobalId) as link
from [LikeCounter] x
where PortalId=1 and LanguageId=1
) as t
GROUP BY itemid, globalid, title, preview, previewimage, previewimage_alt, link
ORDER BY COUNT(*) desc
The query is over a view that holds records of objects being "liked". Since the objects can be published in multiple places, and the view was setup to allow for filtering for a certain place, it requires a distinct before grouping the records to find out the view count (that's the reason for the additional query for the "link" column).
Is a nested SELECT statement possible in one linq statement?
The inner query is no problem:
(from x in LikeCounter
where x.PortalId==1 && x.LanguageId==1
select new {x.Id, x.ItemId, x.GlobalId, x.LanguageId, x.Title, x.Preview, x.PreviewImage_alt,
Morelink=(from y in LikeCounter
where y.GlobalId==x.GlobalId
select y.Morelink).FirstOrDefault()
}).Distinct()
But is there a way to extend this with the grouping of the distinct records, that results in just one query to the database ?
Thanks in advance for any input...
Nina
Edit:
the following query almost returns what I want -- but produces multiple queries to the SQL server:
(from y in
((from x in LikeCounter
where x.PortalId==1 && x.LanguageId==1
select new {x.Id, x.ItemId, x.GlobalId, x.LanguageId, x.Title, x.Preview, x.PreviewImage_alt,
Link=(from y in Xparo_LikeCounter
where y.GlobalId==x.GlobalId
select y.Link).FirstOrDefault()
}).Distinct())
group y by y.GlobalId into grp
select new {Data=grp, Count= grp.Count()}).OrderByDescending (x => x.Count)
I Think the below should work but i can't really test it. No idea how many queries it would take either
from subq in (from x in LikeCounter
where x.PortalId==1 && x.LanguageId==1
select new {x.Id, x.ItemId, x.GlobalId, x.LanguageId, x.Title, x.Preview, x.PreviewImage_alt,
Morelink=(from y in LikeCounter
where y.GlobalId==x.GlobalId
select y.Morelink).FirstOrDefault()
}).Distinct()
group subq by new {TheCount = subq.Id.Count(), subq.Id, subq.ItemId, subq.GlobalId, subq.LanguageId, subq.Title, subq.Preview, subq.PreviewImage_alt, subq.Morelink } into grouped
order by grouped.TheCount descending;