I have an SQL table with many columns(~200).
I want to create a LINQ query to obtain the sum of all rows by column. The result to be one row which represents the SUM of each column.
How can be done this LINQ query?
It's difficult to create a specific .Sum(...) for each column.
double sum = Table.Select(t => t.Amount ?? 0).Sum();
OR
double sum = Table.Sum(t => t.Amount ?? 0);
You could try using:
var results = (from i in yourCollection
group g by i.Column into g
select new
{
ColumnName = i.Column,
ColumnTotal = i.Sum(x => x.Value)
}).ToList();
Use the right tool for the job. This time it isn't Entity Framework. Here is a simple ADO.NET routine:
public double[] SumAllColumns(IDbConnection connection)
{
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = "SELECT * FROM YourTable";
using (var reader = cmd.ExecuteReader())
{
var values = new double[reader.FieldCount];
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
values[i] += reader.GetDouble(i);
}
}
return values;
}
}
}
The method returns an array with the sum of each column.
var sums = (from c in columns
group c by c.columnName into g
select new
{
SumCol1 = g.Sum(x => x.Col1),
SumCol2 = g.Sum(x => x.Col2)
}).SingleOrDefault;
To access the variables in a console application for example...
Console.Write(sums.SumCol1.ToString() + " : " + sums.SumCol2.ToString());
I've used this solution:
from res in datacTx.Table
where ...
group re by re.id into g
select new
{
col1 = g.Sum(x => x.col1),
col2 = g.Sum(x => x.col2),
...
};
but I can't access now any of the values or I can't convert the result into a list in which each column represent an entry in the list.
Until now I've used this, to access the values of linq query:
foreach (var propertyInfo in res.GetType().GetProperties())
{
...
}
but now this is not working because I don't have any properties.
You could use a sqlcommand, which execution returns for each row a result array, then use array.Sum().
Or add a sql computed column.
Related
I want to sum price for all products that is in list.
I called a funtion in linQ query.
Total = t0.TbOfferProducts.Sum(x => Customs.CalculateCurrency(x.TbOffer.Price))
But it didnt recognize my function
I wrote another function for linQ, then I called it. But linQ dont recognize my function.
Error:
LINQ to Entities does not recognize the method 'Double Cal_Price(Int32)' method, and this method cannot be translated into a store expression.
I try other versions but none of them didnt work.Help me please.
myList =
(from t0 in DB.TbProducts
where t0.BoActive == true && t0.BoSoftDeleted == false
let price = Cal_Price(t0.InProductId)
select new ProductActivityInfo
{
ID = t0.InProductId,
Name = t0.StProductName,
Code = t0.StProductCode,
Total = price
})
public double Cal_Price(int productId)
{
double total = 0;
using (MyEntityContext DB = new MyEntityContext())
{
var list = DB.TbOfferProducts.Where(x => x.InProductId == productId);
foreach (var item in list)
{
total += Customs.CalculateCurrency(item.TbOffer.Price);
}
}
return total;
}
EF Core is tryng to build SQL but fails when found custom compiled method in query. Correct Total on the client side:
// calculate sum by grouping
var offerPrices =
from op in DB.TbOfferProducts
group op.TbOffer.Price by x.InProductId
select new
{
ProductId = g.Key,
RawPrice = g.Sum()
};
var result =
(from t0 in DB.TbProducts
join op in offerPrices on t0.InProductId equals op.ProductId
where t0.BoActive == true && t0.BoSoftDeleted == false
select new ProductActivityInfo
{
ID = t0.InProductId,
Name = t0.StProductName,
Code = t0.StProductCode,
Total = op.RawPrice
})
.ToList();
// correct Total on the client side
result.ForEach(x => x.Total = Customs.CalculateCurrency(x.Total));
I have a table:
DataTable store_temp = new DataTable();
store_temp.Columns.Add("patn");
store_temp.Columns.Add("rf");
store_temp.Columns.Add("name");
store_temp.Columns.Add("conv");
store_temp.Columns.Add("conv_type");
store_temp.Columns.Add("recorddate");
store_temp.Columns.Add("executiondate");
My C# code :
int i = 0;
var rowsgroups = (from row in store_temp.AsEnumerable().GroupBy(row =>
row.Field<string>("patn"))
.OrderBy((g => g.OrderByDescending(y => y.Field<string("executiondate")).ThenByDescending(y =>
y.Field<string>("rf"))))
select new
{
patn = row.ElementAt(i),
rf_num = ++i,
}).ToArray();
I want the lambda experession, which is equivalent to:
select patn, rf,
> row_number() over( partition by patn order by executiondate,rf )
as rf_num,
name, conv,conv_type, recorddate, executiondate
from store_temp2
But, lambda syntax ... var rowsgroups has just a one row..
I want to show all rows in store_temp.
What should I do to fix the query?
row_number() over(partition by patn order by executiondate, rf)
means in LINQ you need to group by patn, then order each group by executiondate, rf, then use the indexed Select overload to get row numbering inside the group, and finally flatten the result with SelectMany.
With that being said, the equivalent LINQ query could be something like this:
var result = store_temp.AsEnumerable()
.GroupBy(e => e.Field<string>("patn"), (key, elements) => elements
.OrderBy(e => e.Field<string>("executiondate"))
.ThenBy(e => e.Field<string>("rf"))
.Select((e, i) => new
{
patn = key,
rf = e.Field<string>("rf"),
rf_num = i + 1,
name = e.Field<string>("name"),
conv = e.Field<string>("conv"),
conv_type = e.Field<string>("conv_type"),
recorddate = e.Field<string>("recorddate"),
executiondate = e.Field<string>("executiondate")
}))
.SelectMany(elements => elements)
.ToArray();
Try something like this
select new
{
rowNum = store_temp.Rows.IndexOf(row),
patn = row.ElementAt(i),
rf_num = ++i,
}).ToArray();
I don't think you required any groupby as per your required sql
var i=0;
var rowsgroups = (from row in store_temp.AsEnumerable()
orderby row.Field<string>("executiondate") descending,
row.Field<string>("rf") descending
select new
{
patn = row.Field<string>("patn"),
rf_num = ++i,
name = row.Field<string>("name"),
conv = row.Field<string>("conv"),
conv_type = row.Field<string>("conv_type"),
recorddate = row.Field<string>("recorddate"),
executiondate = row.Field<string>("executiondate")
}).ToArray();
I try to group multiple column on the tbl.AsEnumerable(),
I want to group cus, salesman, ppj and curr while the amt_base should be sum up.
Everything fine,
but when i use grp.Sum(r => r.Field<decimal>("amt_base")) on the sum of the amt it shown At least one object must implement IComparable. errors on the foreach ().
var results = from rows in tbl.AsEnumerable()
group rows by new
{
cus = rows["cus"],
salesman = rows["salesman"],
ppj = rows["ppj"],
curr = rows["curr"],
}into grp
orderby grp.Key
select new
{
cus = grp.Key.cus,
nm = grp.First()["nm"],
salesman = grp.Key.salesman,
ppj = grp.Key.ppj,
curr = grp.Key.curr,
amt_base = grp.Sum(r => r.Field<decimal>("amt_base")),
};
DataTable tbl2 = new DataTable();
tbl2.Columns.Add("cus");
tbl2.Columns.Add("nm");
tbl2.Columns.Add("salesman");
tbl2.Columns.Add("ppj");
tbl2.Columns.Add("curr");
tbl2.Columns.Add("amt_base");
decimal tamt_base = 0;
foreach (var item in results)
{
DataRow dr2 = tbl2.NewRow();
dr2["cus"] = item.cus;
dr2["nm"] = item.nm;
dr2["salesman"] = item.salesman;
dr2["ppj"] = item.ppj;
dr2["curr"] = item.curr;
dr2["amt_base"] = Math.Round(item.amt_base, 2, MidpointRounding.AwayFromZero);
tbl2.Rows.Add(dr2);
tamt_base += item.amt_base;
}
It can't determine how to order the rows based on an anonymous type comprised of of 4 random columns. It needs to be able to compare each instance to the previous, which is usually done by having your class implement the IComparable interface... but you can't with an anonymous type.
Remove this:
orderby grp.Key
If you really need some sort of ordering, try using an individual field:
orderby grp.Key.cus
void refreshtable()
{
var query = (from x in de.HeaderTrainingAllocations
join y in de.MsTrainings on x.TrainingID equals y.TrainingID
join z in de.MsUsers on x.UserID equals z.UserID
select new
{
x.AllocationID,
x.TrainingID,
z.UserName,
x.TrainingStartDate,
TrainingEndDate = System.Data.Objects.EntityFunctions.AddDays(x.TrainingStartDate, ((y.TrainingDuration - 1) * 7)),
y.TrainingDuration,
x.Capacity
}
);//get all data from tables
dataGridView1.DataSource = query;
for (int i = 0; i < dataGridView1.RowCount; i++)
{
int currentcapacity;
Int32.TryParse(dataGridView1.Rows[i].Cells[6].Value.ToString(),out currentcapacity);
String idA = dataGridView1.Rows[i].Cells[0].Value.ToString(); //read allocation ID on cell 0
var cek = (from x in de.DetailTrainingAllocations
where x.AllocationID==idA
select x).Count(); //to get amount of data in table detailTransaction
dataGridView1.Rows[i].Cells[6].Value =currentcapacity- cek;//this code won't change the value of the rows in datagridview
}
}
This code is working perfectly but the last code didn't work for some reason,the values in row X at column 6 didn't change at all. I have almost no solution for this in my mind.
This is the most direct conversion, although you really should be doing a JOIN on DetailTrainingAllocations, rather than making a loop, doing one query for each record.
void refreshtable()
{
var query = (from x in de.HeaderTrainingAllocations
join y in de.MsTrainings on x.TrainingID equals y.TrainingID
join z in de.MsUsers on x.UserID equals z.UserID
select new
{
x.AllocationID,
x.TrainingID,
z.UserName,
x.TrainingStartDate,
TrainingEndDate = System.Data.Objects.EntityFunctions.AddDays(x.TrainingStartDate, ((y.TrainingDuration - 1) * 7)),
y.TrainingDuration,
x.Capacity
}
).ToList();//get all data from tables
foreach (var z in query)
{
var cek = (from x in de.DetailTrainingAllocations
where x.AllocationID==z.AllocationID
select x).Count(); //to get amount of data in table detailTransaction
z.Capacity-=cek;//this code won't change the value of the rows in datagridview
}
dataGridView1.DataSource = query;
}
I spend a few hours trying to translate simple SQL to lambda LINQ
SELECT ID, AVG(Score) FROM myTable
GROUP BY ID
Any idea?
from t in myTable
group t by new {
t.ID
} into g
select new {
Average = g.Average(p => p.Score),
g.Key.ID
}
or Lambda
myTable.GroupBy(t => new {ID = t.ID})
.Select (g => new {
Average = g.Average (p => p.Score),
ID = g.Key.ID
})
The equivalent in Linq-to-Objects would be something like the below.
var results = from row in myTable
group row by row.Id into rows
select new
{
Id = rows.Key,
AverageScore = rows.Average(row => row.Score)
};
It's only slightly different for an ORM like entity framework. Namely, you would need to go through the data context or an appropriate DbSet/ObjectSet.
var _result = from a in myTable
group a by a.ID into g
select new
{
ID = g.Key.ID,
AverageResult = g.Average(x => x.Score)
}