Need linq query to obtain specific result set - c#

If any one can help here to prepare this linq query.
Below is the table data:
category question answer user
a1 q1 3 u1
a1 q1 5 u2
a1 q2 3 u2
a2 q3 3 u3
a2 q3 2 u4
a3 q4 9 u3
a3 q5 8 u7
a3 q5 2 u9
I need result as below:
group by Category, Question, Result (group with three condition as below).
so, for each category, each question, need to group the result in three form(group by answer (<=3) and one group, answer = 5 and third group answer=8 OR 7 OR 9),
category name Question TotalCount Ans(<=3) Ans(5) Ans(7 or 8 or 9)
a1 q1 2 1 1 0
a1 q2 1 1 0 0
a2 q3 1 1 0 0
.....
I tried by using below query in SQL (it is not perfect query as i need column for result group instead of record).
SELECT
Category, Question,
Count(Ans),
CASE
WHEN Ans = 9 OR Ans = 8 OR ans=7 THEN '9 or 8 or 7'
WHEN Ans = 5 THEN '5'
WHEN Ans <= 3 THEN '<=3'
END as 'ResultGroup'
FROM
SurveyQuestions
GROUP BY
Category, Question, Ans
ORDER BY
Question
Please guide me how to get the result as shown above. I need LINQ query to obtain this result.
thanks

You don't need to group it by answer. Instead filter and count on the answer something like below:
from t in db.Table
group t by new {t.Category, t.Question} into g
order by g.Category
select new
{
CategoryName = t.FirstOrDefault().Category, //might be required to handle null here
Question = t.FirstOrDefault().Question, //might be required to handle null here
TotalCount = t.Count(),
AnsLessEqual3 = t.Where(d => d.Answer<=3).Count(),
Ans5 = t.Where(d => d.Answer = 5).Count(),
Ans789 = t.Where(d => d.Answer = 7 || d.Answer = 8 || d.Answer = 9).Count()
}
Although above query is not tested but I believe it would give you quick start for moving forward.

Related

c# Linq How to write Innter Join using if condition

Here I have Two Tables Like
Employee
Id IsAccepected(bool) AccepectedBy EmpId
1 0 0 E1-1
2 1 2 E1-2
3 1 1 C1-1
Login
Id name
1 John
2 Mick
3 smith
Here my Question if IsAccepected==True then I need to Fetch Accepted By Record from Login Table
var x=(from n i in _db.EMployee
WHERE n.Empid='E1-1'
select n).Tolist();
foreach(var item in x){
if(item.IsAccepected==True){
.......
}
But I don't Need all those is it Possible to Write this condition Within The Linq
i guess you need this sql query need to be in linq right?
select b1.*,isnull((select 1 from A as a1 where a1.AccepectedBy=b1.Id and a1.EmpId='E1-2'),0) as isaccepted from B as b1
Something like below should work:
var x = from e in _db.Employee join l in _db.Login on e.AcceptedBy equals l.ID where e.Accepted == true select l;
Use this code by left join method-
select Login.name,Employee.EmpId from Employee left join Login on Employee.AccepectedBy=Login.Id where Employee.[IsAccepected(bool)]=1

C# Linq using distinct with union

I have a table in db as :
Id Name Stream Version UId Tab Key Value CreatedOn CreatedBy
1 Name1 GOP 1 U1 Tab1 co 1 07/01/2018 S, Adam
2 Name1 GOP 1 U2 Tab1 co 1 07/03/2018 S, Adam
3 Name1 GOP 1 U3 Tab2 st 2 07/03/2018 S, Adam
4 Name1 GOP 2 OR Tab1 co 1 07/02/2018 P, Silver
5 Name2 GOP 1 OR Tab1 co 1 07/02/2018 P, Silver
6 Name3 GOP 0 OR1 Tab0 coe 1 07/02/2018 S, Adam
7 Name3 GOP 0 OR2 Tab1 coe 1 07/02/2018 S, Adam
8 Name2 LNT 3 NE Tab1 st 4 07/01/2018 P, Silver
9 Name2 LNT 3 NE1 Tab1 co 2 07/01/2018 P, Silver
10 Name2 LNT 2 NE2 Tab1 st 3 07/01/2018 P, Silver
11 Name2 LNT 0 NE Tab9 co 5 07/01/2018 R, Henry
12 Name3 TTE 0 TT Tab1 ee 2 07/02/2018 R. Henry
13 Name3 TTE 0 T1 Tab1 ee 2 07/02/2018 R. Henry
I want to write a query that would give me the highest version of set together with distinct version 0.
For this I wrote the query as but this does not get my desired output:
var data = response.GroupBy(x => new { x.Name, x.Stream })
.SelectMany(g => g.OrderByDescending(row => row.Version).Take(1)) //This gives highest version
.Union(response.Where(x => int.Parse(x.Version) == 0)) // This gives version 0
.OrderByDescending(o => o.CreatedOn).ToList();
Desired Output On UI
Id Name Stream Version CreatedOn CreatedBy
4 Name1 GOP 2 07/02/2018 P, Silver //This is shown as 2 is the highest version for Name1 & GOP combination
5 Name2 GOP 1 07/02/2018 P, Silver //This is shown as Name & Stream combination is different
6 Name1 GOP 0 07/02/2018 S, Adam //Version 0 is always shown - Combination of Name & Stream may or may not have more than one 0 version
8 Name2 LNT 3 07/01/2018 P, Silver //This is shown as 3 is the highest version for Name2 & LNT combination
11 Name2 LNT 0 07/01/2018 R, Henry //Version 0 is always shown
12 Name3 TTE 0 07/02/2018 R, Henry //Version 0 is always shown
On the UI I am trying to just show the trimmed down version of a set. When the user clicks on that set I would then show details for all the individual sets within the set.
Right now I only struck with how to update my query so I can get my desired result.
----Updated---
Right now what I got working is individual lists:
var data1 = response.GroupBy(x => new { x.Name, x.Stream})
.SelectMany(g => g.OrderByDescending(row => row.Version).Take(1))
.Where(x => int.Parse(x.Version) != 0)
.OrderByDescending(o => o.CreatedOn).ToList();
The above gives me all latest versions for a given name and stream.
var data2 = response.GroupBy(x => new { x.Name, x.Stream})
.Select(g => g.First())
.Where(x => int.Parse(x.Version) == 0)
.OrderByDescending(o => o.CreatedOn).ToList();
The above gives me all 0 versions for a given name and stream.
I think these individual lists works fine at the moment, but how to merge them.
Is there a way to join/merge these lists together so as to return just a single set. Or if there is a way to merge these 2 linq queries together.
---Updated-----
var set1 = response.GroupBy(x => new { x.Name, x.Stream})
.SelectMany(g => g.OrderByDescending(row => row.Version).Take(1))
.Where(x => int.Parse(x.Version) != 0).ToList();
var set2 = response.GroupBy(x => new { x.Name, x.Stream, x.Version})
.Select(g => g.First())
.Where(x => int.Parse(x.Version) == 0).ToList();
var setmerged = set1.Union(set2).OrderByDescending(o => o.CreatedOn).ToList();
Got it working by above not sure if this is an clean solution.
Wrong use of DISTINCT
This doesn't make sense. DISTINCT is used to filter duplicate rows, which they aren't as only the version number is the same. Where should the DBS know from, which CreatedOn value it should use?
Better solution
What you want is to use GROUP BY in order to group everything with the same version value. Be aware that you'll need to use an aggregate function like MAX()on the other columns in order to use it correctly.
So from the looks of your updated question, you want the top one of each distinct version, name and stream.
According to the dataset you've provided, and the result sets you want, there is no need to do anything special for the 0 version because the conditions for grabbing the distinct version should include the 0 version as well.
You haven't really specified what the order of the version should be so for now I'll assume that the one that was most recently updated is the one you want
response.GroupBy(x => new { x.Name, x.Stream, x.Version })
.SelectMany(g => g.OrderByDescending(row => row.CreatedOn).Take(1))
.ToList();

Grouping records that haven't groups values

Please consider this records:
Id Week Value
-----------------------------
1 1 1000
2 1 1200
3 2 800
4 3 1800
5 3 1100
6 3 1000
I want to group records for 4 weeks but we haven't record for week 4.For Example:
Week Count
---------------------
1 2
2 1
3 3
4 0
How I can do this with linq?
Thanks
First you need an array of weeks then this query might help
var weeks = new List<int>{1,2,3,4}
var q = from w in weeks
join rw in (
from r in table
group r by r.Week into g
select new {week = g.Key, count = g.Count()}) on w equals rw.week into p
from x2 in p.DefaultIfEmpty()
select new {w, count = (x2 != null ? x2.count : 0)};
online result in .net fiddle
You can try
var result = Enumerable.Range(1, 4)
.GroupJoin(table,
week => week,
record => record.Week,
(week, records) => new { Week = week, Count = records.Count() });
As suggested by jessehouwing, the Enumerable.Range will return the possible week numbers to be used as left outer keys within the join.
GroupJoin will then accept as parameters
A lambda/delegate/method that returns the left outer key
A lambda/delegate/method that extracts the right key from your table.
A lambda/delegate/method that builds an item of the result.
Regards,
Daniele.

EF Query Help - Grouping and Sub queries

I have data table (DOCs, which is the DBSet in my context) with below data
ID Code Rev
1 A1 1
2 A1 2
3 A1 3
4 A3 1
5 A2 1
6 A2 2
I need to select the records which has a records for each Code which has the highest Rev. My expected result is
ID Code Rev
3 A1 3
6 A2 2
4 A3 1
The ID column is the PK of the table and Code+Rev is unique.
Note: There are other fields in the table which i need to get for the result. Ideal would be to get a iqueryable (Doc is the model class), i was think of selecting the ID within an inner query and then use that to get the iqueryable of docs.
Thanks in Advance
Try this:
var res = from r in DOCs
where (from c in DOCs
group c by c.Code into g
select new {
localCode = g.Key,
localRev = g.Max(t => t.Rev)
}).Any(x => x.localCode == r.Code && x.localRev == r.Rev)
select r;
res is IQueryable.

Linq Query for EAV design table

I had a situation to use EAV design tables and I am new to this design,I am struck with a select query. Below is my query structure and data.
TABLE1:
Id KeyName
1 Name
2 Age
TABLE2:
ID TABLE1_ID VALUE
1 1 ABC
2 2 12
3 1 CDF
4 2 14
5 1 XYZ
6 2 13
7 1 CSF
8 2 10
EXPECTED OUTPUT: Get all the values which are greater than 12 AND Value contains "C".
i.e.,
Table2_ID Result Table1_KeyName
1 ABC Name
2 12 Age
3 CDF Name
4 14 Age
Options I tried are:
Var temp = (from c in Table2
where c.Value > 12 && c.Table1.KeyName.Contains("C")
Select new
{
ID = c.ID,
Result = C.Value
});
the above query didn't returned any result, as filters(in where clause) are across rows. I even tried "OR" condition in where clause, it returns me everything. Please do help me.
Your query is wrong, did you type it in here or copy and paste it from your work?
Do you have this table setup in an ORM such as Entity Framework? So that there is a relationship setup between table1 and table2, so you don't have to 'join' them?
To be more 'correct' it should be...
Var temp = (from c in Table2
where c.Value > 12 && c.Table1.Name.Contains("C")
Select new
{
ID = c.ID,
Name = c.Table1.Name,
Value = c.Value
});
Or if the relationship isn't in an ORM your using explicitly specify the join as follows:
Var temp = (from c in Table2
join c1 in Table1 on c.Table1_ID equals c1.Id
where c.Value > 12 && c.Table1.Name.Contains("C")
Select new
{
ID = c.ID,
Name = c.Table1.Name,
Value = c.Value
});
Edit: then it should be an OR, not AND
Var temp = (from c in Table2
where c.Value > 12 || c.Value.Contains("C")
Select new
{
ID = c.ID,
Result = c.Value,
KeyName = c.Table1.Name
});

Categories