How can this query be transform to linq
SELECT materialId, SUM(totalAmount) as quantity FROM Inventory
It's the sum part that I don't know how...
query = from inv in context.Inventory
select new MaterialQuantity()
{
MaterialId = inv.materialId,
Quantity = ??
};
EDIT
Trying to sum the value of totalAmount.
It's a view that is
materialId totalSum and other fields
1 5
1 10
1 20
So I want my linq to return me
MaterialId = 1, Quantity = 35
I'm going to give a complete guess here... assuming your inventory has multiple rows with the same materialId and you want to sum in those groups, you could use:
var query = from inv in content.Inventory
group inv.totalAmount by inv.materialId into g
select new { MaterialId = g.Key, Quantity = g.Sum() };
If you're not trying to group though, you'll need to clarify your question. Sample data and expected output would help.
Related
I have such a table in my database:
Id City Country
==============================
1 A X
2 B X
3 C X
4 D X
5 M Y
6 N Y
7 O Y
8 P Y
9 U Z
10 V Z
I want to get Countries with first (minimum) Id from the table. The result set should be like:
Id Country
=================
1 X
5 Y
9 Z
I can get this result with SQL as :
SELECT
MIN(Id) AS Id,
Country
FROM
AllCityList
GROUP BY
Country
ORDER BY
Country ASC
But when I add this view to EntityFramework since MIN() hides PrimaryKey column (Id) I get an error. Hence, I want to convert this query to Linq. How can I write this query in Linq?
You can use GroupBy with Min. The below query groups the data based on Country and selects the Min Id.
return AllCityList.GroupBy(d => d.Country).Select(d =>
{
var first = d.First();
return new { Id = d.Min(x => x.Id), Country = first.Country};
});
Check this dotnetfiddle which demos the scenario.
Also, with using of Min it will make sure to fetch the minimum Id in case the column in not a clustered index.
SELECT MAX(sectionid) AS SectionId,MAX(displayorder) AS DisplayOrder,propertyid AS PropertyId,1 AS IsSpecSection FROM (
SELECT mp.SectionId ,mp.DisplayOrder ,mp.PropertyId FROM
ModelProperties mp
INNER JOIN PropertySections PS ON mp.SectionId =
ps.SectionId
WHERE ps.IsSpecSection = 1 )s
GROUP BY propertyid
I want to convert above query into LINQ, able to do it for selection of single max column but not for multiple.
I haven't tested the code you have to modify the code as you need
using (var dbContext = new YourEntityName())
{
var result = (from mp in dbContext.ModelProperties
join ps in dbContext.PropertySections on mp.SectionId equals ps.SectionId
where ps.IsSpecSection = 1
group a by new { propertyid } into g
select sectionid , MAX(displayorder)AS DisplayOrder,propertyid AS PropertyId, 1 AS IsSpecSection).ToList();
}
Max value in Linq select Within Innerjoin
You can use this code,
var list=(from mp in ModelProperties
join ps in PropertySections on mp.SectionId equals ps.SectionId
where ps.IsSpecSection == 1
group new { mp, ps } by new { mp.PropertyId } into mgrp
from grp in mgrp.DefaultIfEmpty()
select new
{
grp.mp.SectionId,
grp.mp.PropertyId,
grp.mp.DisplayOrder,
grp.ps.IsSpecSection
}).OrderByDescending(x=>x.SectionId).First();
This query helps you to retrieve ModelProperties rows that has matching SectionId in PropertySections and IsSpecSection has the value 1. Matching rows are then grouped by PropertyId. OrderByDescending sort the retrieved results in descending order of SectionId. First() retrieve the rows that has maximum SectionId for each PropertySections as the rows are sorted in descending order of SectionId.
I have reasons to believe that this code can be done much better, and probably doing much more of the work with the query to begin with?
I'll try to explain this.
Each row on my database has either a 1, 2 or 3 value for exercise, and then also a number as rep that could be any number, but in this code I choose to only care for 1-12, so this code selects the row that has the highest value of kilograms (which is a column and has a value on each row) where exercise is 1 and rep is 1, and then 2 and 3 etc. etc. up to 12, then changes exercise to 2 and goes from 1-12 again selecting the top kilograms row.
Does this make sense?
for (var i = 1; i <= 3; i++) {
for (var ii = 1; ii <= 12; ii++) {
var getPR = "SELECT top 1 kg, rep, date FROM Test WHERE exerVariName = 'Comp' AND exercise = #0 AND rep = #1 order by kg desc";
db.Execute(getPR, i, ii);
foreach (var get in db.Query(getPR, i, ii)) {
DateTime Date = get.Date;
var finalDate = Date.ToString("MMM d, yyyy");
var weight = get.kg + "kg";
var reps = "x " + get.rep;
<a>#weight #reps - #finalDate</a>
<br>
}
}
}
I use SQL Server Compact, and it's not a MVC project.
You can select all rows you are interested in with only one query using Group By and MAX aggregated function.
SELECT t.kg, t.rep, t.date
FROM Test t
INNER JOIN
(SELECT MAX(kg) as kg, exercise, rep
FROM Test
WHERE exerVariName = 'Comp'
GROUP BY exercise, rep) i
ON t.exercise = i.exercise AND t.rep = i.rep AND t.kg = i.kg
WHERE t.exerVariName = 'Comp'
Inner query is executed only once. It finds a group identifier (exercise, rep) tuple and a corresponding maximum kg group value.
Then inner query is joined with Test table in order to get "content" of rows (in your case only one additional field date).
Overall performance is quit optimal.
You need only to iterate over results of this query.
See this topic.
Edit:
Exclude multiple (rep, exercise) records having same kg (almost same result as OP's looping)
SELECT kg, rep, exercise, MAX(date)
FROM
(SELECT t.kg, t.rep, t.exercise, t.date
FROM Test t
INNER JOIN
(SELECT MAX(kg) as kg, exercise, rep
FROM Test
WHERE exerVariName = 'Comp'
GROUP BY exercise, rep) i
ON t.exercise = i.exercise AND t.rep = i.rep AND t.kg = i.kg
WHERE t.exerVariName = 'Comp') t
GROUP BY t.kg, t.rep, t.exercise
SELECT kg, rep, date, exercise, rep FROM Test test1 WHERE rep = (SELECT TOP 1 test2.rep FROM Test test2 WHERE test2.exercise = test1.exercise AND test2.rep = test1.rep ORDER BY kg DESC) GROUP BY exercise, rep
Loop over those results and display them.
I have
var result = (from rev in Revisions
join usr in Users on rev.UserID equals usr.ID
join clc in ChangedLinesCounts on rev.Revision equals clc.Revision
select new {rev.Revision,
rev.Date, usr.UserName, usr.ID, clc.LinesCount}).Take(6);
I make a couple of joins on different tables, not relevant for this question what keys are, but at the end of this query my result "table" contains
{Revision, Date, UserName, ID, LinesCount}
Now I execute e GroupBy in order to calculate a total lines count per user.
So..
from row in result group row by row.ID into g {1}
select new {
g.Key,
totalCount = g.Sum(count=>count.LinesCount)
};
So I get a Key=ID, and totalCount=Sum, but
Confusion
I would like to have also other fields in final result.
In my understanding "table" after {1} grouping query consist of
{Revision, Date, UserName, ID, LinesCount, TotalCount}
If my assumption is correct, why I can not do something like this:
from row in result group row by row.ID into g {1}
select new {
g.Key,
g.Revision //Revision doesn't exist ! Why ??
totalCount = g.Sum(count=>count.LinesCount)
};
but
from row in result group row by row.ID into g {1}
select new {
g.Key,
Revision = g.Select(x=>x.Revision), //Works !
totalCount = g.Sum(count=>count.LinesCount)
};
Works !, but imo, sucks, cause I execute another Select.
Infact looking on LinqPad SQL output I get 2 SQL queries.
Question
Is there any elegant and optimal way to do this, or I always need to run Select
on groupped data, in order to be able to access the fields, that exists ?
The problem is, that you only group by ID - if you'd do that in SQL, you couldn't access the other fields either...
To have the other fields as well, you have to include them in you group clause:
from row in result group row by new { row.ID, row.Revision } into g
select new {
g.Key.ID,
g.Key.Revision
totalCount = g.Sum(count=>count.LinesCount)
};
The problem here is your output logically looks something like this:
Key = 1
Id = 1, Revision = 3587, UserName = Bob, LinesCount = 34, TotalCount = 45
Id = 1, Revision = 3588, UserName = Joe, LinesCount = 64, TotalCount = 54
Id = 1, Revision = 3589, UserName = Jim, LinesCount = 37, TotalCount = 26
Key = 2
Id = 2, Revision = 3587, UserName = Bob, LinesCount = 34, TotalCount = 45
Id = 2, Revision = 3588, UserName = Joe, LinesCount = 64, TotalCount = 54
Id = 2, Revision = 3589, UserName = Jim, LinesCount = 37, TotalCount = 26
Much like if you were to perform a an SQL GROUP BY, an value is either part of the key and thus unique per group, or is in the details and thus is repeated multiple times and possibly different for each row.
Now, logically, it might be that Revision and UserName are unique for each Id but Linq has no way to know that (the same as SQL has no way to know that).
To solve this you'll need to some how specify which revision you want. For instance:
Revision = g.FirstOrDefault(x => x.Revision)
To avoid the multiple SQL problem you would need to use an aggregate function that can be translated in to SQL since most SQL dialects do not have a first operator (the result set is considered unordered so technically no item is "first").
Revision = g.Min(x => x.Revision)
Revision = g.Max(x => x.Revision)
Unfortunately Linq does not have a min/max operator for strings, so although the SQL might support this, Linq does not.
In this case you can produce an intermediate result set for the Id and totals, then join this back to the original set to get the details, eg:
from d in items
join t in (
from t in items
group by t.Id into g
select new { Id = g.Key, Total = g.Sum(x => x.LineCount) }
) on d.Id equals t.Id
select new { Id = d.Id, Revision = d.Revision, Total = t.Total }
Revision doesn't exist in your second example because it's not a member of IGrouping<T>, in IGrouping<T> you have a Key property, and it's also an IEnumerable<T> for all the rows grouped together. Thus each of those rows has a Revision, but there is no Revision for the grouping itself.
If the Revision will be the same for all rows with the same ID, you could use FirstOrDefault() so that the select nets at most one answer:
from row in result group row by row.ID into g {1}
select new {
g.Key,
Revision = g.Select(x=>x.Revision).FirstOrDefault(),
totalCount = g.Sum(count=>count.LinesCount)
};
If the Revision is not unique per ID, though, you'd want to use an anonymous type as #Tobias suggests for the grouping, then you will get a grouping based on ID and Revision.
I want to return the depart number that is not found Employee Table by comparing Department table.
Person Table
ID name salary job commision DeptID
--------------------------------------------------------------
P001 Jon 2000 Manager NULL 1
P002 Skeet 1000 Salesman 2000 1
P003 James 2340 Developer NULL 2
P004 greed 4500 Developer NULL 2
P005 Joel 1330 Salesman 1200 1
P006 Deol 5000 Architect NULL 2
Department Table
DeptID DeptName
1 Management
2 Software
3 ERP
SQL
select DeptId from dept
where deptId not in (select deptid from person)
When i try to execute the below code
LINQ
var qry = from n in context.Persons
where n.DeptID !=
(from m in context.Depts select m.DeptId)
select new { DeptID = n.DeptID };
I receive the following error
Operator '!=' cannot be applied to operands of type 'int?' and 'System.Linq.IQueryable'
var qry = from n in context.Persons
where n.DeptID !=
(from m in context.Depts select m.DeptId).FirstOrDefault()
select new { DeptID = n.DeptID };
You are trying to compare DeptID with a collection 1 or more department Ids. Even if there would only logically be one result for a DeptID, syntactically you need to specify that you want the first hit.
Suggested rephrasing:
var q = from m in context.Depts
where
!context.Persons.Select(p => p.DeptID).Contains(m.DeptID)
select new { DeptID = m.DeptID };
It sounds that your DeptID field in SQL is set to allow nulls. In that case you'd probably want something along the lines of this:
var qry = from n in context.Persons
where n.DeptID.Value !=
(from m in context.Depts select m.DeptId)
select new { DeptID = n.DeptID.Value };
I think it should be something like that. I tried to get a list of DeptID's first and then implement a NOT IN with contains :
var deptIDs = context.Persons
.Where( p => !context.Depts
.Select(d => new {DeptID = d.DeptID})
.Contains( p.DeptID )
)
.Select( p => new { DeptID = n.DeptID } );