Get multiple MAX values from single query across multiple columns using Linq - c#

I'm trying to select the max values of 3 columns from a table. All the fields being returned from the query are Strings.
What I have sofar
var step1 = from result in t_hsbc_staging_trts_derived_tbl_ac_balance.AsQueryable()
where result.branch_no == brnchnu
&& result.deal_id == dealid
&& result.group_mbr == grpmem
&& result.ac_type != "RMC"
select result ;
var branch = from result in step1
select new {ccbranch = result.cc_branch.Max()};
var sect = from result in step1
select new { ccsect = result.cc_sect.Max()};
var dept = from result in step1
select new { ccdept = result.cc_dept.Max()};
foreach (var result in branch)
{
string cc_branch = result.ccbranch.ToString();
}
The error I'm getting at the foreach statement is:
Sequence operators not supported for type 'System.String'.
There must be an easier way to just get the max values from this table?

You are calling the Max() function on result.cc_branch which is itself a string. Even if it was successful, it would return the character of the string that has the largest unicode number, i.e.
string s = "one-two-three";
Console.WriteLine(s.Max()); // returns 'w'
Since I assume that is not what you want, and that you want the largest branch / section / department value, you can use:
string branch = (from result in step1 select result.cc_branch).Max();
string sect = (from result in step1 select result.cc_sect).Max();
string dept = (from result in step1 select result.cc_dept).Max();

Related

how to get a linq query result to int

below query return a single value eg 50. I want it be assign to int so I can do some calculation with that value. how can I do this
var LTLimit = from a in dbavailability.tACLicenseTypes
where a.License_Type == "Long Term"
select a.Limit;
string AST = "";
I'm not completely clear on what you're asking, but presumably the type of data returned by your Linq query is not int, and you want to convert it to int? If so, simply convert it to an int:
var LTLimit = (from a in dbavailability.tACLicenseTypes
where a.License_Type == "Long Term"
select a.Limit).ToList();
int LTLimitInt = 0
if (!int.TryParse(LTLimit.First(), out LTLimitInt))
{
Console.WritLine("LTLimit is not a number!")
}
Since you've updated your question, here's a solution to convert the returned number to an int, multiply it by 2, then convert the result to a string:
var LTLimit = (from a in dbavailability.tACLicenseTypes
where a.License_Type == "Long Term"
select a.Limit).ToList();
int LTLimitInt = 0;
string multipliedResultStr = string.Empty;
if (!int.TryParse(LTLimit.First(), out LTLimitInt))
{
Console.WritLine("LTLimit is not a number!")
}
else
{
multipliedResult = (LTLimitInt * 2).ToString();
Console.WriteLine(string.Format("Result is {0}, multipliedResult ));
}
Edit;
Corrected code to take first item from list.
The following code is one way to retrieve the first integer returned in your query:
var LTLimit = (from a in dbavailability.tACLicenseTypes
where a.License_Type == "Long Term"
select a.Limit).ToList();
int limit = LTLimit[0];
What is the return type of the query?
If the returned type is of another primative data type like a string, then you can try to convert it to an integer using :
var i = Convert.ToInt32(LTLimit);
Or using :
int.TryParse(LTLimit, out var i);
However, it would be better if the data was stored in the correct type in the first place.
You can use Sum() after where() for value of object property
like this bonus.Where(b => b.Id == x.key && b.RequiredScore.HasValue).Sum(b => b.RequiredScore.Value);

Update IQueryable result before using as join in next query

I need to use Linq to Entity Framework to query a LOCATION table to get the record of the location code with the MAX effective date, then use that result as a join in the next query.
I BELIEVE I need to do convert before the IQueryable is used, because I have that last clause in the second query where I want to exclude records where the FLOOR code is in the excludedSchools list. That excludedSchools list will have the newLocationCode in it.
So, I need to update the values in the IQueryable result before I use it. Can I do this? Here is my code:
using (var db = new TheContext())
{
IQueryable<LocationTable> locatinWithMaxEffDate =
(from lc in db.LocationTable
where lc.EFF_STATUS == "A" && lc.EFFDT <= DateTime.Now
group lc by lc.LOCATION into g
select g.OrderByDescending(x => x.EFFDT).FirstOrDefault()
);
foreach (var location in locatinWithMaxEffDate.ToList())
{
string newLocationCode;
if(codeMappingDictionary.TryGetValue(location.FLOOR, out newLocationCode))
{
// how do I update locatinWithMaxEffDate FLOOR value
// with newLocationCode so it works in the query below?
location.FLOOR = newLocationCode;
}
}
var query =
(from fim in db.PS_PPS_FIM_EE_DATA
join mloc in locatinWithMaxEffDate on fim.LOCATION equals mloc.LOCATION
where
fim.EMPL_STATUS == PsPpsFimEeData.EmployeeStatusValues.Active
&& fim.AUTO_UPDATE == PsPpsFimEeData.AutoUpdateValues.Enabled
&& includeJobCodes.Contains(fim.JOBCODE)
&& !excludedSchools.Contains(mloc.FLOOR)
select new PpsAdministratorResult
{
SchoolId = mloc.FLOOR,
Login = fim.OPRID,
EmployeeId = fim.EMPLID,
}
With the code above, the locatinWithMaxEffDate does not have the updated FLOOR values. I can see why this is, but can't seem to fix it.
So far, I have tried introducing another list to ADD() the new location record to, then casting that as an IQueryable, but I get an error about primitive vs concrete types.
I decided to make things easier on myself. Since both sets of data are very small (fewer than 1000 records each) I call take the entire set of data as an annonymous type:
using (var db = new TheContext())
{
IQueryable<LocationTable> locatinWithMaxEffDate =
(from lc in db.LocationTable
where lc.EFF_STATUS == "A" && lc.EFFDT <= DateTime.Now
group lc by lc.LOCATION into g
select g.OrderByDescending(x => x.EFFDT).FirstOrDefault()
);
var query =
(from fim in db.PS_PPS_FIM_EE_DATA
join mloc in locatinWithMaxEffDate on fim.LOCATION equals mloc.LOCATION
where
fim.EMPL_STATUS == PsPpsFimEeData.EmployeeStatusValues.Active
&& fim.AUTO_UPDATE == PsPpsFimEeData.AutoUpdateValues.Enabled
&& includeJobCodes.Contains(fim.JOBCODE)
select new PpsAdministratorResult
{
SchoolId = mloc.FLOOR,
Login = fim.OPRID,
EmployeeId = fim.EMPLID,
}
}
Then, just work with the two objects:
List<PpsAdministratorResult> administratorList = new List<PpsAdministratorResult>();
foreach (var location in query.ToList())
{
string newLocationCode;
if(schoolCodeMappings.TryGetValue(location.SchoolId, out newLocationCode)) // && newLocationCode.Contains(location.LOCATION))
{
location.SchoolId = newLocationCode;
}
if( !excludedSchools.Contains(location.SchoolId) )
{
administratorList.Add(location);
}
}
Now, I have the list I want.

How do I drill down to specific data in my LINQ query result?

I want to drill down into a particular item in my data and output the list of results to the output window. My query result looks like this
private IEnumerable<DataRow> _data;
var query = from data in this._data
group data by data.Field<string>("Form Name") into groups //same as Form ID
select new
{
formName = groups.Key,
items = from d in groups
group d by d.Field<string>("Item Name") into grps
let name = grps.Key
let documentIDGroups = grps.GroupBy(t => t.Field<string>("Document ID"))
let documentIDGroupsCount = documentIDGroups.Count()
let distinctDocumentValueCount = from data in documentIDGroups
select new
{
docID = data.Key,
distinctDocValueCount = data.Where(t => string.IsNullOrEmpty(t.Field<string>("Document Value").Trim()) == false).Select(t => t.Field<string>("Document Value")).Distinct().Count()
}
let sum = distinctDocumentValueCount.Sum(t => t.distinctDocValueCount)
let distinctItemsNames = from data in grps
select data.Field<string>("Item Name").Distinct().Count()
let count = distinctItemsNames.Count()
select new
{
itemName = name,
documentIDGroups,
documentIDGroupsCount,
averageChoices = Math.Round(((decimal)sum / documentIDGroupsCount), 2),
distinctDocumentValueCount,
sum
}
};
So on that query result I want to drill down into a particular form name, and from there get a particular Item Name and so on
so the first step is to get the grouping of items and I have
var items = from d in query where d.formName == "someName" select d.items;
but I don't know how to isolate the items by a particular string.
I want to do the following
var item = from d in items where d.itemName == "anItemName" select d;
But I don't know the syntax.
Use the .FirstOrDefault extension if you expect a single item to be returned from your query. SO:
var item = (from d in items where d.itemName == "anItemName" select d).FirstOrDefault();

LINQ get find all with id in list

I am trying to figure out non query way to do return a list of all objects if their ID is in test list. Example below:
Hero - table
Columns: id = INT , name = STRING, age = INT, power = INT;
var testList = {1,2,3};
var secondArray = {};
foreach (var id in testList )
{
// check if ID in database
var item = db.Hero.ToList().Find(o => o.Id = id);
if( item != null)
{
secondArray.push(item);
}
}
Now i have seen this whole thing done in single line but cannot remember how it was done.
The result i am after is List of all objects containing that have ids 1,2,3.
You have to use Contains on testList:
var secondArray= db.Hero.Where (h=> testList.Contains(h.Id))
How about
var result = db.Hero.Where(x => testList.Contains(x.Id));
This would hit DB just once instead of 3 times.

Inner Join on Entity Framework

There is a table name Product:
|ProductID|ProductName|
1 abc
2 xyz
and there is another table Product Status.
The column Result in the below has three values:
Result
Value | Meta
0 Not checked
1 Failed
2 Passed
ProductCheckList
ID(AutoGenerated) | ProductID(Foreign Key) | Stage | Result |
1 1 1 1
2 1 2 2
In this table every product has to go through five different stages. If the product passes all the stages then the product is given quality checked status , If the product fails any on of the stages is is given as quality failed and send back to production.
I have to show a list of all the products with there quality status and depending on its quality state highlight the row with different row color. We are using Entity Framework and I am new to this.
I have thought of making a wrapper class for this.
Public class ProductWrapper
{
public Product product{get;set;}
Public string QualityStatus{get;set;}
public string BgColor {get;set;}
}
I am writing this LINQ query:
UtilitiesEntities context = new UtilitiesEntities();
List<ProductWrapper> wrapperList = new List<ProductWrapper>();
var request = from product in context.Product
join productCheck in context.ProductCheckList
on product.productId equals productCheck .productID
// may be do group by or something i get the result and assign the values.
select new List<ProductWrapper>
{
};
I am not able to write the query and add the where condition to fetch the result a list of wrapper class to pass to my view with the desired result.
If I understood correctly your request, you want something like this:
string goodQualityColor = "Green";
string badQualityColor = "Red";
string notCheckedColor = "Gray";
string notCheckedStatus = "Not Checked";
string failedStatus = "Failed";
string passedStatus = "Passed";
Dictionary<int,string> results= new Dictionary<int,string>();
results.Add(2,goodQualityColor);
results.Add(1,badQualityColor);
results.Add(0,notCheckedColor);
Dictionary<int,string> qualityStatuses = new Dictionary<int,string>();
results.Add(2,passedStatus);
results.Add(1,failedStatus);
results.Add(0,notCheckedStatus);
var request = (from product in context.Product
join productCheck in context.ProductCheckList
on product.productId equals productCheck.productID
select new
{
Product = product,
QualityStatus = productCheck.Result,
Result = productCheck.Result
}).ToList();
var finalResults = (from req in request
select new ProductWrapper
{
Product = req.Product,
QualityStatus = qualityStatuses.FirstOrDefault(s => s.Key == req.QualityStatus).Value,
BgColor = results.FirstOrDefault (s => s.Key == req.Result).Value
}).ToList<ProductWrapper>();
I would create an outer join using the into keyword and then do my statusCheck in the select part.
Could would look something like this :
var data = (from product in context.Product
join productCheck in context.ProductCheckList on product.productId equals productCheck.productID into productChecks
select new ProductWrapper
{
product = product,
passedBool = productChecks.All(pc => pc.Result == 2) && productChecks.Count() == 5
}).ToList();

Categories