What could be the LINQ query for this SQL?
SELECT PartId, BSId,
COUNT(PartId), MAX(EffectiveDateUtc)
FROM PartCostConfig (NOLOCK)
GROUP BY PartId, BSId
HAVING COUNT(PartId) > 1
I am actually grouping by two columns and trying to retrieve max EffectiveDateUtc for each part.
This is what I could write. Stuck up on pulling the top record based on the date.
Also not sure, if this is a optimal one.
//Get all the parts which have more than ONE active record with the pat
//effective date and for the same BSId
var filters = (from p in configs
?.GroupBy(w => new
{
w.PartId,
w.BSId
})
?.Select(g => new
{
PartId = g.Key.PartId,
BSId = g.Key.BSId,
Count = g.Count()
})
?.Where(y => y.Count > 1)
select p)
?.Distinct()?.ToList();
var filteredData = (from p in configs
join f in filters on p.PartId equals f.PartId
select new Config
{
Id = p.Id,
PartId = p.PartId,
BSId = p.BSId,
//EffectiveDateUtc = MAX(??)
}).OrderByDescending(x => x.EffectiveDateUtc).GroupBy(g => new { g.PartId, g.BSId }).ToList();
NOTE: I need the top record (based on date) for each part. Was trying to see if I can avoid for loop.
The equivalent query would be:
var query =
from p in db.PartCostConfig
group p by new { p.PartId, p.BSId } into g
let count = g.Count()
where count > 1
select new
{
g.Key.PartId,
g.Key.BSId,
Count = count,
EffectiveDate = g.Max(x => x.EffectiveDateUtc),
};
If I understand well, you are trying to achieve something like this:
var query=configs.GroupBy(w => new{ w.PartId, w.BSId})
.Where(g=>g.Count()>1)
.Select(g=>new
{
g.Key.PartId,
g.Key.BSId,
Count = g.Count(),
EffectiveDate = g.Max(x => x.EffectiveDateUtc)
});
Related
I'm trying to convert my sql query to linq, i confused about sum and grouping,
this is my query
SELECT
produk.supplier,
SUM(transaksi.jumlah_transaksi),
SUM(transaksi.nominal_transaksi),
operasional.nominal
FROM
transaksi INNER JOIN produk ON transaksi.id_produk = produk.id_produk
LEFT JOIN
(SELECT
operasional.id_supplier,
SUM(nominal) AS nominal
FROM
operasional) operasional
ON operasional.id_supplier = produk.id_supplier
GROUP BY produk.supplier
output should be
like this
Progress
i am just trying with linq query like this without grouping
var result = from t in db.transaksi
join p in db.produk on t.id_produk equals p.id_produk
from op in
(
from o in db.operasional
select new
{
id_supplier = o.id_supplier,
nominal = o.nominal
}
).Where(o => o.id_supplier == p.id_supplier).DefaultIfEmpty()
select new
{
nama_supplier = p.supplier,
jumlah_transaksi = t.jumlah_transaksi,
nominal_transaksi = t.nominal_transaksi,
biaya_operasional = op.nominal
};
and result query from my linq still like this
SELECT
`p`.`supplier`,
`t`.`jumlah_transaksi`,
`t`.`nominal_transaksi`,
`t1`.`nominal`
FROM
`transaksi` `t`
INNER JOIN `produk` `p`
ON `t`.`id_produk` = `p`.`id_produk`
LEFT JOIN `operasional` `t1`
ON `t1`.`id_supplier` = `p`.`id_supplier`
Solved
and this is my full linq
var result = from t in db.transaksi
join p in db.produk on t.id_produk equals p.id_produk
from op in
(
from o in db.operasional
group o by o.id_supplier into g
select new
{
id_supplier = g.First().id_supplier,
nominal = g.Sum(o => o.nominal)
}
).Where(o => o.id_supplier == p.id_supplier).DefaultIfEmpty()
select new
{
nama_supplier = p.supplier,
jumlah_transaksi = t.jumlah_transaksi,
nominal_transaksi = t.nominal_transaksi,
biaya_operasional = op.nominal
};
var grouped = result
.GroupBy(x => x.nama_supplier)
.Select(x => new
{
nama_supplier = x.Key,
jumlah_transaksi = x.Sum(s => s.jumlah_transaksi),
nominal_transaksi = x.Sum(s => s.nominal_transaksi),
biaya_operasional = x.Select(s => s.biaya_operasional).First()
});
Try to use GroupBy (in following code result is your query from code above):
var grouped = result
.GroupBy(x => x.nama_supplier)
.Select(x => new {
nama_supplier = x.Key,
sum1 = x.Sum(s => s.jumlah_transaksi),
sum1 = x.Sum(s => s.nominal_transaksi),
nominal = x.Select(s => s.biaya_operasional).First()
})
Code is not checked so use it just as idea.
I would like to do a group by and on that a sum and a count. I don't seem to be able to create the solution in linq. How can I convert my query to linq?
SELECT HistoricalBillingProductGroup,
COUNT(*),
BillingPeriod,
SUM(TotalMonthlyChargesOtcAndMrc)
FROM [x].[dbo].[tblReport]
group by BillingPeriod, HistoricalBillingProductGroup
order by BillingPeriod
This is what I got sofar in Linq
var result =
context.Reports.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.Select(x => new StatisticsReportLine
{
HistoricalBillingGroup = x.FirstOrDefault().HistoricalBillingProductGroup,
BillingPeriod = x.FirstOrDefault().BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
})
.ToString();
The query I get from this is enormous and takes a very long time to load. In SQL its a matter of milliseconds. I hardly doubt this is the solution.
I believe the calls to x.FirstOrDefault() are the source of your problem. Each one of these will result in a very costly inner query inside the SELECT clause of the generated SQL.
Try using the Key property of the IGrouping<T> instead :
var result = context.Reports
.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.OrderBy(x => x.Key.BillingPeriod)
.Select(x => new StatisticsReportLine
{
HistoricalBillingProductGroup = x.Key.HistoricalBillingProductGroup,
BillingPeriod = x.Key.BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
});
Or if you prefer query syntax:
var result =
(from r in context.Reports
group r by new { r.BillingPeriod, r.HistoricalBillingProductGroup } into g
orderby g.Key.BillingPeriod
select new StatisticsReportLine
{
HistoricalBillingProductGroup = g.Key.HistoricalBillingProductGroup,
BillingPeriod = g.Key.BillingPeriod,
CountOfRows = g.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
});
You could try this one:
var result = context.Reports
.GroupBy(x => new {x.BillingPeriod, x.HistoricalBillingProductGroup})
.Select(x => new StatisticsReportLine
{
HistoricalBillingGroup = x.Key.HistoricalBillingProductGroup,
BillingPeriod = x.Key.BillingPeriod,
CountOfRows = x.Count(),
SumOfAmount = x.Sum(p => p.TotalMonthlyChargesOtcAndMrc) ?? 0
}).ToString();
In the above query you make a group by on two properties, BillingPeriod and HistoricalBillingProductGroup. So in each group that will be created, you will have a key, that will be consisted by these two properties.
I am trying to construct a LINQ query in C# that will give me a list of distinct values from a column in a dataset with a count for each row. The results would look like this.
State Count
AL 55
AK 40
AZ 2
Here is the SQL that does that.
SELECT name, COUNT(*) AS count
FROM architecture arch
GROUP BY name
ORDER BY name
I've figured out the LINQ to get the DISTINCT values which is.
var query = ds.Tables[0].AsEnumerable()
.OrderBy(dr1 => dr1.Field<string>("state"))
.Select(dr1 => new {state = dr1.Field<string>("state")})
.Distinct().ToList();
But I can't figure out how to get the COUNT(*) for each distinct value to work in LINQ. Any idea how I can add that into the LINQ query?
You need to group your results based on State and the Select count from the group like:
var query = ds.Tables[0].AsEnumerable()
.GroupBy(r => r.Field<string>("state"))
.Select(grp => new
{
state = grp.Key,
Count = grp.Count()
})
.OrderBy(o => o.state)
.ToList();
Group all rows by value of state column. Then order groups by grouping key. And last step - project each group into anonymous object with grouping key (state) and count of rows in group:
var query = ds.Tables[0].AsEnumerable()
.GroupBy(r => r.Field<string>("state"))
.OrderBy(g => g.Key)
.Select(g => new { State = g.Key, Count = g.Count() })
.ToList();
Query syntax will look like (I'll skip converting to list, to avoid mixing syntaxes):
var query = from r in ds.Tables[0].AsEnumerable()
group r by r.Field<string>("state") into g
orderby g.Key
select new {
State = g.Key,
Count = g.Count()
};
I think you need GroupBy
var query = ds.Tables[0].AsEnumerable()
.GroupBy(dr1 => dr1.Field<string>("state"))
.Select(g => new {state = g.Key, count = g.Count())
.ToList();
Why bother with Distinct, when you can translate your SQL query to LINQ almost word-for-word? You can do it like this:
var query = ds.Tables[0].AsEnumerable()
.GroupBy(dr1 => dr1.Field<string>("state"))
.Select(g => new {
State = g.Key
, Count = g.Count()
})
.OrderBy(p => p.State)
.ToList();
This produces a list of {State, Count} pairs. If you prefer a dictionary of state-to-count, you can change your query like this:
var query = ds.Tables[0].AsEnumerable()
.GroupBy(dr1 => dr1.Field<string>("state"))
.ToDictionary(g => g.Key, g => g.Count());
var query = ds.Tables[0].AsEnumerable()
.GroupBy(x=>x.Field<string>("state"))
.Select( g => new{
state = g.Key,
count = g.Count()
});
Guess what, the equivalent of group by is group by :)
var query = from dr1 in ds.Tables[0].AsEnumerable()
group dr1 by dr1.Field<string>("state") into state
select new { State = state.Key, Count = state.Count() };
var stat = from row in ds.Tables[0].AsEnumerable()
group row by new
{
Col1 = row["Name"],
} into TotalCount
select new
{
ActionName = TotalCount.Key.Col1,
ActionCount = TotalCount.Count(),
};
I am getting data from multiple tables by joining and i want to group data on particular column value but after group by statement i can access my aliases and their properties. What mistake i am making?
public List<PatientHistory> GetPatientHistory(long prid)
{
using(var db = new bc_limsEntities())
{
List<PatientHistory> result =
(from r in db.dc_tresult
join t in db.dc_tp_test on r.testid equals t.TestId into x
from t in x.DefaultIfEmpty()
join a in db.dc_tp_attributes on r.attributeid equals a.AttributeId into y
from a in y.DefaultIfEmpty()
where r.prid == prid
group new {r,t,a} by new {r.testid} into g
select new PatientHistory
{
resultid = r.resultid,
bookingid = r.bookingid,
testid = r.testid,
prid = r.prid,
attributeid = r.attributeid,
result = r.result,
Test_Name = t.Test_Name,
Attribute_Name = a.Attribute_Name,
enteredon = r.enteredon,
Attribute_Type = a.Attribute_Type
}).ToList();
return result;
}
}
You're doing this wrong way. As been said by Jon after grouping the sequences with aliases r,t,a doesn't exist. After grouping you receive the sequence g with sequances of r,t,a in each element of g. If you want get one object from each group (for example most recent) you should try this:
List<PatientHistory> result =
(from r in db.dc_tresult
join t in db.dc_tp_test on r.testid equals t.TestId into x
from t in x.DefaultIfEmpty()
join a in db.dc_tp_attributes on r.attributeid equals a.AttributeId into y
from a in y.DefaultIfEmpty()
where r.prid == prid
group new {r,t,a} by new {r.testid} into g
select new PatientHistory
{
resultid = g.Select(x => x.r.resultid).Last(), // if you expect single value get it with Single()
// .... here add the rest properties
Attribute_Type = g.Select(x => x.a.Attribute_Type).Last()
}).ToList();
I appreciated this question so I thought I would add another potential usage case. I would like feedback on what the cleanest approach is to getting table information through a group operation so that I can project later in the select operation. I ended up combining what the OP did which is to pass objects into his group clause and then used the g.Select approach suggested by YD1m to get table information out later. I have a LEFT JOIN so I'm defending against nulls :
// SQL Query
//DECLARE #idCamp as Integer = 1
//
//select *,
//(select
//count(idActivityMaster)
//FROM tbActivityMasters
//WHERE dftidActivityCategory = A.idActivityCategory) as masterCount
//FROM tbactivitycategories A
//WHERE idcamp = #idCamp
//ORDER BY CategoryName
int idCamp = 1;
var desiredResult =
(from c in tbActivityCategories
.Where(w => w.idCamp == idCamp)
from m in tbActivityMasters
.Where(m => m.dftidActivityCategory == c.idActivityCategory)
.DefaultIfEmpty() // LEFT OUTER JOIN
where c.idCamp == idCamp
group new {c, m} by new { m.dftidActivityCategory } into g
select new
{
idActivityCategory = g.Select(x => x.m == null ? 0 : x.m.dftidActivityCategory).First(),
idCamp = g.Select(x => x.c.idCamp).First(),
CategoryName = g.Select(x => x.c.CategoryName).First(),
CategoryDescription = g.Select(x => x.c.CategoryDescription).First(),
masterCount = g.Count(x => x.m != null)
}).OrderBy(o=> o.idActivityCategory);
desiredResult.Dump("desiredResult");
If I just use a basic group approach I get the results but not the extra column information. At least I can't find it once I group.
var simpleGroup = (from c in tbActivityCategories
.Where(w => w.idCamp == idCamp)
.OrderBy(o => o.CategoryName)
from m in tbActivityMasters
.Where(m => m.dftidActivityCategory == c.idActivityCategory)
.DefaultIfEmpty() // LEFT OUTER JOIN
where c.idCamp == idCamp
group m by m == null ? 0 : m.dftidActivityCategory into g
select new
{
// How do I best get the extra desired column information from other tables that I had before grouping
// but still have the benefit of the grouping?
// idActivityCategory = g.Select(x => x.m == null ? 0 : x.m.dftidActivityCategory).First(),
// idCamp = g.Select(x => x.c.idCamp).First(),
// CategoryName = g.Select(x => x.c.CategoryName).First(),
// CategoryDescription = g.Select(x => x.c.CategoryDescription).First(),
// masterCount = g.Count(x => x.m != null)
idActivityCategory = g.Key,
masterCount = g.Count(x => x != null)
});
simpleGroup.Dump("simpleGroup");
Please tear this up. I'm trying to learn and it just seems like I'm missing the big picture here. Thanks.
UPDATE : Cleaned up by moving the work into the group and making the select more straight forward. If I had known this yesterday then this would have been my original answer to the OP question.
int idCamp = 1;
var desiredResult =
(from c in tbActivityCategories
.Where(w => w.idCamp == idCamp)
from m in tbActivityMasters
.Where(m => m.dftidActivityCategory == c.idActivityCategory)
.DefaultIfEmpty() // LEFT OUTER JOIN
where c.idCamp == idCamp
group new { c, m } by new
{ idActivityCategory = m == null ? 0 : m.dftidActivityCategory,
idCamp = c.idCamp,
CateGoryName = c.CategoryName,
CategoryDescription = c.CategoryDescription
} into g
select new
{
idActivityCategory = g.Key.idActivityCategory,
idCamp = g.Key.idCamp,
CategoryName = g.Key.CateGoryName,
CategoryDescription = g.Key.CategoryDescription,
masterCount = g.Count(x => x.m != null)
}).OrderBy(o => o.idActivityCategory);
desiredResult.Dump("desiredResult");
I have an ArrayList of type RawResults where RawResults is a location and a date
public class RawResult
{
public string location { get; set; }
public DateTime createDate {get; set; }
public RawResults(string l, DateTime d)
{
this.location = l;
this.createDate = d;
}
}
I would like to use LINQ to populate a list containing each distinct location and the number of times it appears in my arraylist. If I able to do it in SQL it would look like this
select
bw.location,
count(*) as Count
from
bandwidth bw,
media_log ml
where
bw.IP_SUBNET = ml.SUBNET
group by bw.location
order by location asc
later I will also have to do the same thing, but within a given date range.
UPDATE
this is the query that was run to get all of the data in rawData
SELECT
MEDIASTREAM.BANDWIDTH.LOCATION, MEDIASTREAM.MEDIA_LOG.CREATE_DATE
FROM
MEDIASTREAM.BANDWIDTH INNER JOIN
MEDIASTREAM.MEDIA_LOG ON MEDIASTREAM.BANDWIDTH.IP_SUBNET =
MEDIASTREAM.MEDIA_LOG.SUBNET
Now I need to query the data that was returned in rawData to get different result sets. I have available a List to query.
You can do this:
var results =
(from bw in data.bandwith
join ml in data.media_log on bw.IP_SUBNET equals ml.SUBNET
group bw by bw.location into g
orderby g.Key
select new
{
location = g.Key,
Count = g.Count()
})
.ToList();
Although the ToList is not necessary unless you absolutely need it to be a List<T>. To filter by time, you can just do something like this:
var results =
(from bw in data.bandwith
join ml in data.media_log on bw.IP_SUBNET equals ml.SUBNET
where bw.createDate >= minDate && bw.createDate <= maxDate
group bw by bw.location into g
orderby g.Key
select new
{
location = g.Key,
Count = g.Count()
})
.ToList();
If media_log isn't relevant, you can just omit the join:
var results =
from bw in data.bandwith
group bw by bw.location into g
orderby g.Key
select new
{
location = g.Key,
Count = g.Count()
}
Or in fluent syntax:
var results = data.bandwith
.GroupBy(bw => bw.location, (k, g) => new { location = k, Count = g.Count() })
.OrderBy(r => r.location);
To filter by date, just use this:
var results =
from bw in data.bandwith
where bw.createDate >= minDate && bw.createDate <= maxDate
group bw by bw.location into g
orderby g.Key
select new
{
location = g.Key,
Count = g.Count()
};
Or in fluent syntax:
var results = data.bandwith
.Where(bw => bw.createDate >= minDate && bw.createDate <= maxDate)
.GroupBy(bw => bw.location, (k, g) => new { location = k, Count = g.Count() })
.OrderBy(r => r.location);
Note, to use an ArrayList, or any other non-generic collection type in a Linq query, use the Cast<T> or OfType<T> methods, like this:
var results = bandwithArrayList
.Cast<RawResults>()
.GroupBy(bw => bw.location, (k, g) => new { location = k, Count = g.Count() })
.ToList();
List<RawResult> results = MethodToGetResults();
var locationCount = results
.GroupBy(r => r.location)
.Select(lc => new {Location = lc.location, Count = lc.Count()});