how convert sql to linq - c#

How do I do this
Select top 10 Foo from MyTable
SELECT TOP (30) Item, Descripcion, SUM(Amount) AS Suma
FROM Venat
GROUP BY Item, Descripcion
ORDER BY Suma
in Linq to SQL?
with this only agrup by Item but not Description
var filtroprimeros30 = from nuevo in registrosVipDosAños
group nuevo by nuevo.Item into g
select new
{
Item = g.Key,
Suma = g.Sum(nuevo => nuevo.Amount)
};

Use anonymous type for grouping:
var filtroprimeros30 =
(from nuevo in registrosVipDosAños
group nuevo by new { nuevo.Item, nuevo.Description } into g // here
select new {
g.Key.Item,
g.Key.Description,
Suma = g.Sum(n => n.Amount)
})
.OrderBy(x => x.Suma)
.Take(30);
I'd actually go this way (because query syntax has nice syntax for grouping, but do not have ability to take N items):
var items = from n in registrosVipDosAños
group n by new { n.Item, n.Description } into g
select new {
g.Key.Item,
g.Key.Description,
Suma = g.Sum(x => x.Amount)
};
var topItems = items.OrderBy(x => x.Suma).Take(30);
Query still will be executed only once, but now it's more readable.

syntax alternative
var filtroprimeros30 = registrosVipDosAnos
.GroupBy(m => new {m.Item, m.Description})
.Select(g => new {
Item = g.Key.Item,
Description = g.Key.Description,
Suma = g.Sum(n => n.Amount)
})
.OrderBy(x => x.Suma)
.Take(30);

Related

SQL query to LINQ conversion with nested select statements

I want to convert the following query to LINQ:
SELECT LV.* FROM LowerVehicles LV
INNER JOIN (Select VSerial,MAX(updatedOn) MaxUpdatedOn from LowerVehicles group by vserial) LVG
ON LV.VSerial = LVG.VSerial AND LV.updatedOn = LVG.MaxUpdatedOn
Not knowing your entities classes, here is an approximation. You can use query syntax or fluent syntax. Sometimes one is preferable over the other, and in the case of joins and grouping I prefer to use query syntax.
QUERY SYNTAX
var query = from LV in LowerVehicles
join LVG in (
from r in LowerVehicles
group r by r.vserial into g
select new {VSerial = g.Key, MaxUpdatedOn = g.Max(t => t.updatedOn)})
on LV.VSerial equals LVG.Vserial
and LV.updatedOn equals LVG.MaxUpdatedOn
select LV;
FLUENT SYNTAX
var lvg = LowerVehicles.GroupBy(t => t.vserial)
.Select(g => new {
VSerial = g.Key,
MaxUpdatedOn = g.Max(t => t.updatedOn)
});
var query = LowerVehicles.Join(
lvg,
a => new { a.VSerial, a.updatedOn },
b => new { b.VSerial, b.MaxUpdatedOn },
(a, b) => new { LV = a, LVG = b}
)
.Select(t=> t.LV);
Something like this?
Something.LowerVehicles
.Join(something.LowerVehicles.Select(y => new { y.VSerial, updatedOn = y.updatedOn.Max() }).GroupBy(z => z.VSerial),
x => new { x.VSerial, x.updatedOn },
lvg => new { lvg.VSerial, lvg.updatedOn },
(x, y) => x)

Linq Grouping with a sum

Hi All i have the following code
var deptSalesQuery = from d in db.DashboardFigures
join s in outlets.Split(',').Select(x => int.Parse(x)) on d.OutletNo equals s
where (d.TypeOfinformation == "DEPTSALES")
select new DeptSales
{
Dn = (int)d.Number,
On = d.OutletNo,
Qs = (double)d.Value_4,
Se = (double)d.Value_2,
Si = (double)d.Value_3
};
What i want to do is group the query by 'Dn' which is 'd.Number'and return
the sum of (double)d.Value_4 , (double)d.Value_2 , (double)d.Value_3. I have looked on the forum and some people have asked a similar question but for some reason its not working for me. Can anyone help ?
I have changed the code to
var deptSalesQuery = from d in db.DashboardFigures
join s in outlets.Split(',').Select(x => int.Parse(x)) on d.OutletNo equals s
where (d.TypeOfinformation == "DEPTSALES")
group d by d.Number into newGroupedresult
select new DeptSales
{
Qs = (double)newGroupedresult.Sum(d => d.Value_4),
Se = (double)newGroupedresult.Sum(d => d.Value_2),
Si = (double)newGroupedresult.Sum(d => d.Value_3)
};
but its not grouping, Its showing the individual records. Also I normally have Dn = D.Number, its not allowing me to put this.
deptSalesQuery
.GroupBy(x => x.Number)
.Select(g => new
{
Dn = g.Key,
Sum = g.Sum(x => x.Value_2 + x.Value_3 + Value_4)
});

How to write lambda expression for an sql expression?

I have an SQL expression
select S.SpecialtyName, COUNT(distinct SUC.SiteUserId) as Subscribers
from SiteUserContent SUC Inner join
Specialties S on SUC.SpecialtyId = S.SpecialtyId Inner join
SiteUser SU on SUC.SiteUserId = SU.SiteUserId
where SU.DeletedFlag = 0
group by S.SpecialtyName
Order by S.SpecialtyName
What will be the corresponding LINQ expression for the same?
from suc in context.SiteUserContent
join s in context.Specialties on suc.SpecialtyId equals s.SpecialtyId
join su in context.SiteUser on suc.SiteUserId equals su.SiteUserId
where su.DeletedFlag == 0
select new { suc.SiteUserId, s.SpecialityName } into x
group x by x.SpecialityName into g
orderby g.Key
select new {
SpecialityName = g.Key,
Subscribers = g.Select(i => i.SiteUserId).Distinct().Count()
}
Generated SQL will not be same, but I think result of query execution should be same.
var results = contex.SiteUserContent
.Join(context.Specialties, suc => suc.SpecialtyId, s => s.SpecialtyId, (suc, s) => new { suc, s })
.Join(context.SiteUser, i = i.suc.SiteUserId, su => su.SiteUserId, (i, su) => new { suc = i.suc, s = i.s, su = su })
.Where(i => i.su.DeletedFlag == 0)
.GroupBy(i => i.s.SpecialtyName)
.Select(g => new {
SpecialityName = g.Key,
Subscribers = g.Select(i => i.suc.SiteUserId)
.Distinct()
.Count()
})
.OrderBy(i => i.SpecialityName);

Linq to SQL with GroupBy and Detail - Is there a better way to do this?

I have some SQL and am trying to make the equivalent in LINQ. This is the SQL:
SELECT Categories.CategoryDescription, Categories.CategoryType AS Type,
Categories.Category, COUNT(CategoryLinks.OrgID) AS CountOfOrgs
FROM CategoryLinks
INNER JOIN Categories ON Categories.CategoryID = CategoryLinks.CategoryID
GROUP BY Categories.Category, Categories.CategoryType, Categories.CategoryDescription
ORDER BY CategoryDescription ASC
Essentially, I want a list of everything from the Categories table and a count of the number of OrgId's in the CategoryLinks table that links to it.
Below is the query I am performing at the moment. There has to be a more efficient way to do this. Am I wrong?
var cnts = (from c in db.Categories
join cl in db.CategoryLinks on c.CategoryID equals cl.CategoryID
group new { c, cl } by new
{
c.CategoryID
} into g
select new
{
CategoryID = g.Key.CategoryID,
categoryCount = g.Count()
});
var results = (from c in db.Categories
join cn in cnts on c.CategoryID equals cn.CategoryID
select new
{
c.CategoryID,
c.CategoryDescription,
c.CategoryType,
Category = c.Category1,
cn.categoryCount
});
I think you want to use the GroupJoin method:
Categories.GroupJoin(
CategoryLinks,
x => x.CategoryID,
y => y.CategoryID,
(x,y) => new{
x.CategoryID,
x.CategoryDescription,
x.CategoryType,
Category = x.Category1,
CategoryCount = y.Count() })
In query syntax, this is written as join..into:
from c in db.Categories
join cl in db.CategoryLinks on c.CategoryID equals cl.CategoryID into catGroup
select new
{
c.CategoryID,
c.CategoryDescription,
c.CategoryType,
Category = c.Category1,
CategoryCount = catGroup.Count()
}
Try this:
var bbb = categories.Join(categoryLinks, c => c.CategoryID, cl => cl.CategoryId, (c, cl) => new {c, cl})
.GroupBy(g => g.c)
.Select(g => new {count = g.Count(), Category = g.Key});
It returns count and all data that is in Category. We group by all columns in category and place result in new anonymous type variable that contains 2 properties: Count, that contains count and Category that is of type Category and contains all data that is in category row.
If you want, you can rewrite it as:
var bbb = categories.Join(categoryLinks, c => c.CategoryID, cl => cl.CategoryId, (c, cl) => new {c, cl})
.GroupBy(g => g.c)
.Select(g => new
{
CategoryID = g.Key.CategoryId,
CategoryDescription = g.Key.CategoryDescription,
CategoryType = g.Key.CategoryType,
Category = g.Key.Category1,
categoryCount = g.Count()
});

Group By Multiple Columns

How can I do GroupBy multiple columns in LINQ
Something similar to this in SQL:
SELECT * FROM <TableName> GROUP BY <Column1>,<Column2>
How can I convert this to LINQ:
QuantityBreakdown
(
MaterialID int,
ProductID int,
Quantity float
)
INSERT INTO #QuantityBreakdown (MaterialID, ProductID, Quantity)
SELECT MaterialID, ProductID, SUM(Quantity)
FROM #Transactions
GROUP BY MaterialID, ProductID
Use an anonymous type.
Eg
group x by new { x.Column1, x.Column2 }
Procedural sample:
.GroupBy(x => new { x.Column1, x.Column2 })
Ok got this as:
var query = (from t in Transactions
group t by new {t.MaterialID, t.ProductID}
into grp
select new
{
grp.Key.MaterialID,
grp.Key.ProductID,
Quantity = grp.Sum(t => t.Quantity)
}).ToList();
For Group By Multiple Columns, Try this instead...
GroupBy(x=> new { x.Column1, x.Column2 }, (key, group) => new
{
Key1 = key.Column1,
Key2 = key.Column2,
Result = group.ToList()
});
Same way you can add Column3, Column4 etc.
Since C# 7 you can also use value tuples:
group x by (x.Column1, x.Column2)
or
.GroupBy(x => (x.Column1, x.Column2))
C# 7.1 or greater using Tuples and Inferred tuple element names (currently it works only with linq to objects and it is not supported when expression trees are required e.g. someIQueryable.GroupBy(...). Github issue):
// declarative query syntax
var result =
from x in inMemoryTable
group x by (x.Column1, x.Column2) into g
select (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity));
// or method syntax
var result2 = inMemoryTable.GroupBy(x => (x.Column1, x.Column2))
.Select(g => (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity)));
C# 3 or greater using anonymous types:
// declarative query syntax
var result3 =
from x in table
group x by new { x.Column1, x.Column2 } into g
select new { g.Key.Column1, g.Key.Column2, QuantitySum = g.Sum(x => x.Quantity) };
// or method syntax
var result4 = table.GroupBy(x => new { x.Column1, x.Column2 })
.Select(g =>
new { g.Key.Column1, g.Key.Column2 , QuantitySum= g.Sum(x => x.Quantity) });
You can also use a Tuple<> for a strongly-typed grouping.
from grouping in list.GroupBy(x => new Tuple<string,string,string>(x.Person.LastName,x.Person.FirstName,x.Person.MiddleName))
select new SummaryItem
{
LastName = grouping.Key.Item1,
FirstName = grouping.Key.Item2,
MiddleName = grouping.Key.Item3,
DayCount = grouping.Count(),
AmountBilled = grouping.Sum(x => x.Rate),
}
Though this question is asking about group by class properties, if you want to group by multiple columns against a ADO object (like a DataTable), you have to assign your "new" items to variables:
EnumerableRowCollection<DataRow> ClientProfiles = CurrentProfiles.AsEnumerable()
.Where(x => CheckProfileTypes.Contains(x.Field<object>(ProfileTypeField).ToString()));
// do other stuff, then check for dups...
var Dups = ClientProfiles.AsParallel()
.GroupBy(x => new { InterfaceID = x.Field<object>(InterfaceField).ToString(), ProfileType = x.Field<object>(ProfileTypeField).ToString() })
.Where(z => z.Count() > 1)
.Select(z => z);
var Results= query.GroupBy(f => new { /* add members here */ });
A thing to note is that you need to send in an object for Lambda expressions and can't use an instance for a class.
Example:
public class Key
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
This will compile but will generate one key per cycle.
var groupedCycles = cycles.GroupBy(x => new Key
{
Prop1 = x.Column1,
Prop2 = x.Column2
})
If you wan't to name the key properties and then retreive them you can do it like this instead. This will GroupBy correctly and give you the key properties.
var groupedCycles = cycles.GroupBy(x => new
{
Prop1 = x.Column1,
Prop2= x.Column2
})
foreach (var groupedCycle in groupedCycles)
{
var key = new Key();
key.Prop1 = groupedCycle.Key.Prop1;
key.Prop2 = groupedCycle.Key.Prop2;
}
group x by new { x.Col, x.Col}
.GroupBy(x => (x.MaterialID, x.ProductID))
.GroupBy(x => x.Column1 + " " + x.Column2)
For VB and anonymous/lambda:
query.GroupBy(Function(x) New With {Key x.Field1, Key x.Field2, Key x.FieldN })

Categories