c# - Group by and having with two counts in Linq - c#

How can I write the follow query with Linq in C#?
SELECT MAX(A2.LINHA_PLANILHA)
FROM MD_IMP_FORCA_VENDA_DADOS_A2 A2
WHERE A2.LINHA <> '0'
AND TRIM(A2.SETORES) IS NOT NULL
AND A2.LINHA_PLANILHA <> 1
AND USUARIO = V_USUARIO
GROUP BY A2.LINHA, A2.BRICK
HAVING COUNT(A2.BRICK) > 1 AND COUNT(DISTINCT A2.SETORES) > 1;
I thought to do this:
var result = from r in dataTable.AsEnumerable()
where r.Field<string>(1) != "0"
&& r.Field<string>(2).Trim() != null
&& r.Field<Int32>(0) != 1
group r by new {Linha = r.Field<string>(1), Brick = r.Field<string>(3) } into temp
where temp.Count() > 1
select new { MaxLinha = (from r2 in temp select r2.Field<Int32>(0)).Max()};
But I don't know how to put the two COUNTS of HAVING clause in Linq query.
Any help would be appreciated.
Thanks
Zago

Perhaps:
var query = db.MD_IMP_FORCA_VENDA_DADOS_A2
.Where(x => x.LINHA != "0"
&& x.SETORES != null
&& x.SETORES.Trim() != ""
&& x.LINHA_PLANILHA <> 1
&& x.USUARIO = x.V_USUARIO
)
.GroupBy(x => new { x.LINHA, x.BRICK })
.Where(g => g.Count() > 1 && g.Select(x => x.SETORES).Distinct().Count() > 1)
.Select(g => g.Max(x => x.LINHA_PLANILHA));

Related

Difference between LINQ Lambda and SQL statement

I have the following lambda statement:
var resources = Db.Resource.Where(w => w.ResValue.Any(a => a.ApplicationFk == applicationPk) && w.CategoryFk == (categoryId ?? w.CategoryFk ) && w.IsEditable);
if (cultureIdsMissing!= null)
{
resources = resources.Where(w => w.ResValue.Any(a => cultureIdsMissing.Any(aa => aa == a.CultureFk) && a.Value == string.Empty));
}
This is not returning the result which I want, which is returned by:
SELECT Resource.ResourcePk, Resource.CategoryFk, Resource.Name, Resource.IsEditable, ResValue.ApplicatieFk, ResValue.CultureFk, ResValue.Value
FROM Resource
INNER JOIN ResValue ON Resource.ResourcePk = ResValue.ResourceFk
WHERE (ResValue.ApplicatieFk = 6)
AND (Resource.IsEditable = 1)
AND (ResValue.Value = '')
AND (ResValue.CultureFk = 1 OR ResValue.CultureFk = 2)
Not that cultureIdsMissing is a List containing both the numbers 1 and 2.
What am I missing or doing wrong with the lambda query?
I think you have to remove && w.CategoryFk == (categoryId ?? w.CategoryFk ) from your linq lemda expression. if categoryId = 1 then it will take only records with value 1. So try after remove that. Your linq code should be this.
var resources = Db.Resource.Where(w => w.ResValue.Any(a => a.ApplicationFk == applicationPk)&& w.IsEditable);
if (cultureIdsMissing!= null)
{
resources = resources.Where(w => w.ResValue.Any(a => cultureIdsMissing.Any(aa => aa == a.CultureFk) && a.Value == string.Empty));
}
You should take it from your sql statement :
Db.Resource
.Join(Db.ResValue
, rs => rs.ResourcePk
, resV => resv.resourceFk
, (rs, resv) => new { res = rs, resV = resV })
.Where(w => w.resv.ApplicatieFk == 6
&& w.res ==1
&& resv.Value == string.empty()
&& (resv.CultureFk == 1 || resv.CultureFk == 2))
It's not tested so maybe it won't work on first try.
I would translate the SQL to query comprehension syntax. In general, convert phrases in query comprehension order, use table aliases as range variables (or create range variables), and put unary/overall aggregate functions (such as TOP, DISTINCT or SUM) as function calls outside the whole query. For your SQL,
var ans = from r in Resource
where r.IsEditable == 1
join rv in ResValue on r.ResourcePk equals rv.ResourceFk
where rv.ApplicatieFk == 6 && rv.Value == "" && (rv.CultureFk == 1 || rv.CultureFk == 2)
select new { r.ResourcePk, r.CategoryFk, r.Name, r.IsEditable, rv.ApplicatieFk, rv.CultureFk, rv.Value };

Improve performance in linq query - trying to change the query from subquery to join

I am doing the below linq query which is costing me a lot and this query is in a loop which I can not avoid and I have to do it in C# which also I can not avoid. I have lot of logic above the linq query and after the query. I wanted to check if I can change anything on the query to improve the performance at least a little bit.
lstDataTable.Where(i => i.Field<int>("ALLL_Snapshot_ID") == 20 &&
i.Field<int>("ALLL_Analysis_Segment_Group_Column_ID") == 5 &&
i.Field<DateTime>("OriginationDate") > startingSnapshotDate &&
i.Field<DateTime>("OriginationDate") <= endingSnapshotDate &&
snapshotDataWithDate.Select(j => j.Field<string>
("MaturityDateBorrowerIdNoteNumberKey")).Contains(i.Field<string>
("MaturityDateBorrowerIdNoteNumberKey")) &&
snapshotDataWithDate.Select(j => j.Field<string>
("OriginationDateBorrowerIdNoteNumberKey")).Contains(i.Field<string>
("OriginationDateBorrowerIdNoteNumberKey")))
.Select(i => i.Field<Decimal>("BalanceOutstanding") + i.Field<Decimal>
("UndisbursedCommitmentAvailability")).Sum();
where lstDataTable and snapshotDataWithDate are IEnumerable of DataRow.
I tried above query using join but it is not joining properly. The difference between the two results is way high. Below is the query I tried using join
(from p in lstDataTable
join t in snapshotDataWithDate on p.Field<string>
("MaturityDateBorrowerIdNoteNumberKey") equals t.Field<string>
("MaturityDateBorrowerIdNoteNumberKey") &&
p.Field<string>("OriginationDateBorrowerIdNoteNumberKey") equals
t.Field<string>("OriginationDateBorrowerIdNoteNumberKey")
where p.Field<int>("ALLL_Analysis_Segment_Group_Column_ID") ==
SegmentGroupCECLSurvivalRateObj.ALLL_Segment_Group_Column_ID &&
p.Field<DateTime>("OriginationDate") > startingSnapshotDate &&
p.Field<DateTime>("OriginationDate") <= endingSnapshotDate
select p.Field<Decimal>("BalanceOutstanding") + p.Field<Decimal>
("UndisbursedCommitmentAvailability")).Sum();
Try this query, I have changed some expressions in where clause.
lstDataTable.Where(i => i.Field<int>("ALLL_Snapshot_ID") == 20 &&
i.Field<int>("ALLL_Analysis_Segment_Group_Column_ID") == 5 &&
i.Field<DateTime>("OriginationDate") > startingSnapshotDate &&
i.Field<DateTime>("OriginationDate") <= endingSnapshotDate &&
snapshotDataWithDate.Any(j => j.Field<string>
("MaturityDateBorrowerIdNoteNumberKey") == i.Field<string>
("MaturityDateBorrowerIdNoteNumberKey")) &&
snapshotDataWithDate.Any(j => j.Field<string>
("OriginationDateBorrowerIdNoteNumberKey") == i.Field<string>
("OriginationDateBorrowerIdNoteNumberKey")))
.Select(i => i.Field<Decimal>("BalanceOutstanding") + i.Field<Decimal>
("UndisbursedCommitmentAvailability")).Sum();
Perhaps pulling out the Field accesses will provide a small amount of optimization?
var snapshotDataConvertedMDB = snapshotDataWithDate.Select(r => r.Field<string>("MaturityDateBorrowerIdNoteNumberKey")).ToList();
var snapshotDataConvertedODB = snapshotDataWithDate.Select(r => r.Field<string>("OriginationDateBorrowerIdNoteNumberKey")).ToList();
var ans = lstDataTable
.Select(r => new {
ALLL_Snapshot_ID = r.Field<int>("ALLL_Snapshot_ID"),
ALLL_Analysis_Segment_Group_Column_ID = r.Field<int>("ALLL_Analysis_Segment_Group_Column_ID"),
OriginationDate = r.Field<DateTime>("OriginationDate"),
MaturityDateBorrowerIdNoteNumberKey = r.Field<string>("MaturityDateBorrowerIdNoteNumberKey"),
OriginationDateBorrowerIdNoteNumberKey = r.Field<string>("OriginationDateBorrowerIdNoteNumberKey"),
BalanceOutstanding = r.Field<Decimal>("BalanceOutstanding"),
UndisbursedCommitmentAvailability = r.Field<Decimal>("UndisbursedCommitmentAvailability")
})
.Where(i => i.ALLL_Snapshot_ID == 20 &&
i.ALLL_Analysis_Segment_Group_Column_ID == 5 &&
i.OriginationDate > startingSnapshotDate &&
i.OriginationDate <= endingSnapshotDate &&
snapshotDataConvertedMDB.Contains(i.MaturityDateBorrowerIdNoteNumberKey) &&
snapshotDataConvertedODB.Contains(i.OriginationDateBorrowerIdNoteNumberKey))
.Select(i => i.BalanceOutstanding + i.UndisbursedCommitmentAvailability)
.Sum();

Can my two linq lines of code be combined?

I'm not sure how to do this since I'm only familiar with the basic form or Linq.
Here are my two sets of code:
var qry = from x in CustomersChecks.CustomersChecksList
where x.RoutingNumber == routingnumber &&
x.BankAccountNumber == bankAccountNumber &&
x.Branch > 0 &&
x.AccountNumber > 0
orderby x.Name
select x;
var qry2 = qry.GroupBy(x => new { x.Branch, x.AccountNumber}).Select(x => x.First()).ToList();
Ultimately, I want to get my first query in order of Branch + Account Number distinctly.
Can they be combined or is what I have the only way to do this?
The quick and dirty solution is just to add the GroupBy chain to the end of the first query.
var qry = (from x in CustomersChecks.CustomersChecksList
where x.RoutingNumber == routingnumber &&
x.BankAccountNumber == bankAccountNumber &&
x.Branch > 0 &&
x.AccountNumber > 0
orderby x.Name
select x).GroupBy(x => new { x.Branch, x.AccountNumber})
.Select(x => x.First())
.ToList();
Or do the following by incorrupating the group by into the exist query syntax
var qry = (from x in CustomersChecks.CustomersChecksList
where x.RoutingNumber == routingnumber &&
x.BankAccountNumber == bankAccountNumber &&
x.Branch > 0 &&
x.AccountNumber > 0
orderby x.Name
group x by new { x.Branch, x.AccountNumber} into grp
select grp.First()).ToList();
var qry = CustomersChecks.CustomersChecksList.Where(x =>
x.RoutingNumber == routingnumber &&
x.BankAccountNumber == bankAccountNumber &&
x.Branch > 0 &&
x.AccountNumber > 0).OrderBy(x => x.Name)
.GroupBy(x => new { x.Branch, x.AccountNumber})
.Select(x => x.First())
.ToList();

linq using IN Operator in split comma values

I am getting the following results for
string[] proj = Pid.Split(',');
"1032,1222" --> [0]=1032,[1]=1222
but I want to use in LINQ query. This is my LINQ query. Where to use it and how to use it?
string[] proj = Pid.Split(',');
var data2 = (from p in Db.emp.AsEnumerable()
join r in Db.use on p.EmployeeId equals r.EmployeeId
join q in Db.proo on p.EmployeeId equals q.EmpId
where (q.IsDelete == false && p.IsDelete == false && p.RoleID != 1 && p.RoleID != 2 && q.ProId == Convert.ToInt32(Pid))
select new GroupSelectedModel {
Text = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(p.FirstName + " " + p.LastName),
Value = r.UserId.ToString(),
StatusId = Convert.ToInt32(p.Status)
})
.Distinct().ToList().OrderBy(r => r.Text);
return data2.OrderBy(p => p.StatusId).ToList();
Please check above mentioned code.
When you need IN, you have to invert it, and use Contains(). Your post is not very clear, but I think you're asking for something like this (note you need to use a List instead of an array):
List<string> proj = new List<string>(Pid.Split(','));
where (q.IsDelete == false && p.IsDelete == false && p.RoleID != 1 && p.RoleID != 2 && proj.Contains(q.ProId))

Linq Min in Select new & Multiple GroupBy columns

I want to write following query in Linq
INSERT INTO INOUTNEW (CODE,INDATE,TIME_DATE1,INOUTFLAG,TIME_FLD1,TIME_FLD2,TIME_FLD3)
SELECT CODE,MIN(INDATE),TIME_DATE1,'I',TIME_FLD1,TIME_FLD2,'31/05/2015' FROM INOUT
WHERE TIME_FLD1='T0003' AND INDATE >= '31/05/2015' AND INDATE <= '31/05/2015'
AND TIME_DATE1='31/05/2015'
GROUP BY CODE,TIME_DATE1,TIME_FLD1,TIME_FLD2
SO I am trying this :-
var data = ctx.tblInOut.Where(m => m.CompanyId == companyId && m.Time_Field1 == item.ShiftCode && m.InDate == StrInStart && m.InDate <= StrInEnd && m.Time_Date1 == InputDate).Select(m =>
new
{
EmployeeId = m.EmployeeId,
InDate = Min(m.InDate),
Time_Date1 = m.Time_Date1,
InOutFlag = m.InOutFlag
}).ToList();
I am stuck in Min Part. How to get Min in Select? And How to add multiple GroupBy in Linq?
Try something like this:
var data = ctx.tblInOut
.Where(m =>
m.CompanyId == companyId &&
m.Time_Field1 == item.ShiftCode &&
m.InDate == StrInStart &&
m.InDate <= StrInEnd &&
m.Time_Date1 == InputDate
)
.GroupBy(m =>
new {
m.Code,
m.Time_Date1,
m.Time_FLD1,
m.Time_FLD2
})
.Select(g =>
new
{
m.Key.Code,
InDate = m.Min(gg => gg.InDate),
m.Key.Time_Date1,
Something = "I",
m.Key.Time_FLD1,
m.Key.Time_FLD2,
SomeDate = "31/05/2015"
}).ToList();
To get Min, you must group first - otherwise it's trying to call Min on a single element.
.Key simply references the key of the group (in this case, a tuple of Code, Date1, Time_FLD1, Time_FLD2)

Categories