I am trying to convert below SQL to LINQ query and I am stuck with filtering results using the Match in Left outer Join.
SELECT #batchID , IQ1.ID, #environment , 'IRD', IQ1.ReportingDate, IQ1.Match
FROM (
SELECT TD.*, RD.Match
FROM TransactionDetail TD
INNER JOIN .dbo.Measure M ON M.InternalID = TD.MetricCode-- and TD.BatchID = 'e07f9855-b286-4406-9189-5cfb2a7914c8'
LEFT OUTER JOIN (
SELECT tmp.ID, tmp.ReportingDate, 1 AS Match
FROM tmp
) AS RD ON RD.ID = M.Frequency AND RD.ReportingDate = TD.ReportingDate
WHERE RD.Match IS NULL AND
TD.BatchID = #batchID AND
NOT EXISTS (SELECT TransactionFailureReasonID FROM TransactionDetailFailureReasons R WHERE R.TransactionDetailID = TD.ID and R.TransactionFailureReasonID = 'NRD') AND
NOT EXISTS (SELECT TransactionFailureReasonID FROM TransactionDetailFailureReasons R WHERE R.TransactionDetailID = TD.ID and R.TransactionFailureReasonID = 'RDP') AND
NOT EXISTS (SELECT TransactionFailureReasonID FROM TransactionDetailFailureReasons R WHERE R.TransactionDetailID = TD.ID and R.TransactionFailureReasonID = 'RDF')
) AS IQ1
I have so far achieved below,
// Prepare data for left outer join
var rd = (from tt in result
select new { ID = tt.Id, tt.ReportingDate });
// inner join
var td = TransactionDetail.Join(
MesureTb,
t => t.MetricCode,
m => m.InternalId,
(t, m) => new
{
t.Id,
t.RowAction,
t.BatchId,
t.TrustCode,
t.MetricCode,
t.ReportingDate,
t.Value,
t.UpperBenchmark,
t.LowerBenchmark,
m.InternalId,
Frequency = m.Frequency
});
// left outer join
var failureTransactionDetail = (from p in td
join q in rd on new { ReportingDate = (DateTime)p.ReportingDate, ID = p.Frequency } equals new { q.ReportingDate, q.ID }
into LJ
//select new { p.Id, p.BatchId, p.ReportingDate, RD = q.ReportingDate, q.ID, p.Frequency });
from value in LJ.DefaultIfEmpty()
//where p.BatchId == batchId
select new {p.BatchId, p.Id, Match = 1, p.ReportingDate } into DJ
// LEFT OUTER JOIN
where DJ.BatchId == batchId
////&& DJ.Match == 0
&& !(TransactionDetailFailureReasons.Any(m => m.TransactionDetailId == DJ.Id && m.TransactionFailureReasonId == "NRD"))
&& !(TransactionDetailFailureReasons.Any(m => m.TransactionDetailId == DJ.Id && m.TransactionFailureReasonId == "RDP"))
&& !(TransactionDetailFailureReasons.Any(m => m.TransactionDetailId == DJ.Id && m.TransactionFailureReasonId == "RDF"))
select new { DJ.Id, DJ.ReportingDate, DJ.BatchId } );
My question being how i can achieve similar result as 1 AS Match does in SQL in Linq.
Could someone please guide me? Currently the SQL query returns 2 results based on Match value as null, but the LInq returns 8 results since it is not filtering the Match on Left join.
Any help is much appreciated.
Thanks in advance.
I'm just taking a stab at helping you out here because the question is a little unclear. But just comparing your sql statement to your linq query I can see that you may be trying to filter where: RD.Match IS NULL? If that assumption is correct then there is problem with your linq query.
Given the following objects:
public class TransactionDetail
{
public TransactionDetail(int id,
int batchId,
int metricCode,
DateTime reportingDate)
{
Id = id;
BatchId = batchId;
MetricCode = metricCode;
ReportingDate = reportingDate;
}
public int Id { get; }
public int BatchId { get; }
public int MetricCode { get; }
public DateTime ReportingDate { get; }
}
public class Measure
{
public Measure(int internalId,
int frequency)
{
InternalId = internalId;
Frequency = frequency;
}
public int InternalId { get; }
public int Frequency { get; }
}
public class Tmp
{
public Tmp(int id,
DateTime reportingDate)
{
Id = id;
ReportingDate = reportingDate;
}
public int Id { get; }
public DateTime ReportingDate { get; }
}
Sample Code:
static void Main(string[] args)
{
var transactionDetails = new List<TransactionDetail>
{
new TransactionDetail(id: 1, batchId: 1, metricCode: 1, reportingDate: new DateTime(2019, 1, 1)),
new TransactionDetail(id: 2, batchId: 1, metricCode: 2, reportingDate: new DateTime(2019, 1, 1))
};
var matches = new List<Measure>
{
new Measure(internalId: 1, frequency: 1),
new Measure(internalId: 2, frequency: 3)
};
var temporaryList = new List<Tmp>
{
new Tmp(1, new DateTime(2019, 1, 1)),
};
var transDetails = transactionDetails.Join(
matches,
t => t.MetricCode,
m => m.InternalId,
(t, m) => new
{
t.Id,
t.BatchId,
t.MetricCode,
t.ReportingDate,
m.InternalId,
m.Frequency
})
.ToList();
var failureTransactionDetail = transDetails
.GroupJoin(temporaryList,
trandetail => new { trandetail.ReportingDate, Id = trandetail.Frequency },
tmp => new { tmp.ReportingDate, tmp.Id },
(trandetail, tmp) => new { trandetail, tmp })
.SelectMany(t => t.tmp.DefaultIfEmpty(), (t, value) => new { t, value, Matches = 1 })
.Where(arg => !arg.t.tmp.Any());
Console.WriteLine(JsonConvert.SerializeObject(failureTransactionDetail, Formatting.Indented));
Console.ReadLine();
}
Examine the output and you'll see that you don't need Match = 1. .Where(arg => !arg.t.tmp.Any()) would be the equivalent to RD.Match IS NULL in your sql query.
Hope that puts you in the right direction.
Related
I have a list with a column value like "0000000385242160714132019116002239344.ACK" i need to take last 6 digits from this value like "239344" without extension(.ack) when binding to the list.
And i need to find the sum of Salary field also.
My query looks like below.
var result = from p in Context.A
join e in B on p.Id equals e.Id
join j in Context.C on e.CId equals j.CId
where (e.Date >= periodFrom && e.Date <= periodTo)
group new
{
e,
j
} by new
{
j.J_Id,
e.Date,
e.Es_Id,
e.FileName,
j.Name,
e.ACK_FileName,
p.EmpSalaryId,
p.Salary
} into g
orderby g.Key.CId, g.Key.Es_Id, g.Key.Date, g.Key.FileName
select new
{
CorporateId = g.Key.CId,
ProcessedDate = g.Key.Date,
EstID = g.Key.Es_Id,
FileName = g.Key.FileName,
Name = g.Key.Name,
ack = g.Key.ACK_FileName,
EmpSalaryId = g.Key.EmpSalaryId,
Salary=g.Key.Salary
};
var Abc=result.ToList();
var result = (from p in Context.A
join e in B on p.Id equals e.Id
join j in Context.C on e.CId equals j.CId
where (e.Date >= periodFrom && e.Date <= periodTo)
group new { e, j } by new
{
j.J_Id,
e.Date,
e.Es_Id,
e.FileName,
j.Name,
ACK_FileName = e.ACK_FileName.Substring(e.ACK_FileName.IndexOf(".ACK") - 7, 11),
p.EmpSalaryId,
p.Salary
} into g
orderby g.Key.CId, g.Key.Es_Id, g.Key.Date, g.Key.FileName
select new
{
CorporateId = g.Key.CId,
ProcessedDate = g.Key.Date,
EstID = g.Key.Es_Id,
FileName = g.Key.FileName,
Name = g.Key.Name,
ack = g.Key.ACK_FileName,
EmpSalaryId = g.Key.EmpSalaryId,
Salary = g.Sum(item => item.Salary)
}).ToList();
Im tryig to transform a SP, into a linq query
This is my SP right now :
UPDATE PatientAlertsSummary
SET IsViewed =1
WHERE PatientID IN (SELECT PatientID FROM PatientTherapist WHERE TherapistID=#TherapistID)
I tried to make a query linq code and this is (so far) my linq query:
I came across some difficulty with doing this
var query = from pas in context.PatientAlertsSummaries
where pas.PatientID.Contains(from pt in context.PatientTherapists where pt.TherapistID == therapistid )
select pas;
foreach (var item in query)
{
item.IsViewed = true;
}
how can I make it right ?
You could change the query to join on the tables to retrieve the results you want, then update the records accordingly:
var query = from pas in context.PatientAlertsSummaries
join pt in context.PatientTherapists on pas.PatientID equals pt.PatientID
where pt.TherapistID == therapistid
select pas;
foreach (var item in query)
{
item.IsViewed = true;
}
Obviously this is untested and based on your current sql / linq query.
You can do something like this:
public class PatientAlertsSummary
{
public bool IsViewed;
public int PatientID;
}
public class PatientTherapist
{
public int PatientID;
public int TherapistID;
}
public void UpdateIsViewed(PatientAlertsSummary summary)
{
summary.IsViewed = true;
}
[TestMethod]
public void Test1()
{
//UPDATE PatientAlertsSummary
//SET IsViewed =1
//WHERE PatientID IN (SELECT PatientID FROM PatientTherapist WHERE TherapistID=#TherapistID)
var therapistId = 1;
var patientAlertsSummaries = new List<PatientAlertsSummary>() {
new PatientAlertsSummary(){PatientID = 1},
new PatientAlertsSummary(){PatientID = 2},
new PatientAlertsSummary(){PatientID = 3}
};
var PatientTherapists = new List<PatientTherapist>() {
new PatientTherapist(){PatientID = 1 , TherapistID = 1},
new PatientTherapist(){PatientID = 2 , TherapistID = 1},
new PatientTherapist(){PatientID = 3, TherapistID = 2}
};
var updatedPatinets1 = PatientTherapists.
Where(o => o.TherapistID == therapistId).
Join(patientAlertsSummaries,
patientTherapist => patientTherapist.PatientID,
patientAlertsSummary => patientAlertsSummary.PatientID,
(o, p) =>
{
UpdateIsViewed(p);
return p;
}).ToList();
}
I am having fun with LINQ query and kind of stuck at figuring out the correct method to get Count of associated entries.
I have below LINQ query and
var result = (from OR in orders
join OE in order_entries on OR.id equals OE.order_id into temp
from LOE in temp.DefaultIfEmpty()
group LOE by new {OR.user_id, OR.site } into g
select new {
col1 = g.Key.user_id,
col2 = g.Key.site,
count = g.Count() ,
cost = g.Sum( oe => oe.cost)
}
);
this turns to
SELECT
1 AS [C1],
[GroupBy1].[K1] AS [user_id],
[GroupBy1].[K2] AS [site],
[GroupBy1].[A1] AS [C2],
[GroupBy1].[A2] AS [C3]
FROM ( SELECT
[Extent1].[user_id] AS [K1],
[Extent1].[site] AS [K2],
COUNT(1) AS [A1],
SUM([Extent2].[cost]) AS [A2]
FROM [dbo].[orders] AS [Extent1]
LEFT OUTER JOIN [dbo].[order_entries] AS [Extent2] ON [Extent1].[id] = [Extent2].[order_id]
GROUP BY [Extent1].[user_id], [Extent1].[site]
) AS [GroupBy1]
What I am trying to acheive here is replace Count(1) with Count([Extent2].[id]) so in case when there is no entries associated with the order I want to show 0 instead of 1.
Can someone please help me with updating the LINQ query to achieve this ?
UPDATE :
replace with below will return the outcome for what I wanted but this also turns my sql query to perform slower..
g.Where(i => i.orders != null).Count(),
The simplest way is to use subqueries:
var qry = from o in orders
select new {
oid = o.ID,
uid = o.UserId,
site = o.Site,
count = order_entries.Where(oe=>oe.OrderId == o.ID).Count(),
cost = order_entries.Where(oe=>oe.OrderId == o.ID).Sum(oe=>oe.Cost)
};
But if you would like to join two data sets, use this:
var qry = (from o in orders join oe in order_entries on o.ID equals oe.OrderId into grp
from g in grp.DefaultIfEmpty()
select new{
oid = o.ID,
uid = o.UserId,
site = o.Site,
count = grp.Count(),
cost = grp.Sum(e=>e.Cost)
}).Distinct();
I strongly believe in it that second query could be writen in simplest way by using group statement.
Here is a complete LinqPad sample:
void Main()
{
List<TOrder> orders = new List<TOrder>{
new TOrder(1, 1, "Site1"),
new TOrder(2, 1, "Site1"),
new TOrder(3, 2, "Site2"),
new TOrder(4, 2, "Site2"),
new TOrder(5, 3, "Site3")
};
List<TOrderEntry> order_entries = new List<TOrderEntry>{
new TOrderEntry(1, 1, 5.5),
new TOrderEntry(2, 1, 6.2),
new TOrderEntry(3, 1, 4.9),
new TOrderEntry(4, 1, 55.15),
new TOrderEntry(5, 1, 0.97),
new TOrderEntry(6, 2, 2.23),
new TOrderEntry(7, 2, 95.44),
new TOrderEntry(8, 2, 3.88),
new TOrderEntry(9, 2, 7.77),
new TOrderEntry(10, 3, 25.23),
new TOrderEntry(11, 3, 31.13),
new TOrderEntry(12, 4, 41.14)
};
// var qry = from o in orders
// select new {
// oid = o.ID,
// uid = o.UserId,
// site = o.Site,
// count = order_entries.Where(oe=>oe.OrderId == o.ID).Count(),
// cost = order_entries.Where(oe=>oe.OrderId == o.ID).Sum(oe=>oe.Cost)
// };
// qry.Dump();
var qry = (from o in orders join oe in order_entries on o.ID equals oe.OrderId into grp
from g in grp.DefaultIfEmpty()
//group g by g into ggg
select new{
oid = o.ID,
uid = o.UserId,
site = o.Site,
count = grp.Count(),
cost = grp.Sum(e=>e.Cost)
}).Distinct();
qry.Dump();
}
// Define other methods and classes here
class TOrder
{
private int iid =0;
private int uid =0;
private string ssite=string.Empty;
public TOrder(int _id, int _uid, string _site)
{
iid = _id;
uid = _uid;
ssite = _site;
}
public int ID
{
get{return iid;}
set{iid = value;}
}
public int UserId
{
get{return uid;}
set{uid = value;}
}
public string Site
{
get{return ssite;}
set{ssite = value;}
}
}
class TOrderEntry
{
private int iid = 0;
private int oid = 0;
private double dcost = .0;
public TOrderEntry(int _iid, int _oid, double _cost)
{
iid = _iid;
oid = _oid;
dcost = _cost;
}
public int EntryId
{
get{return iid;}
set{iid = value;}
}
public int OrderId
{
get{return oid;}
set{oid = value;}
}
public double Cost
{
get{return dcost;}
set{dcost = value;}
}
}
I'm attempting to translate the following SQL statement to Linq and am having trouble with the multiple joins- I seem to be missing something.
SELECT DISTINCT
Test1 = Table1.Column1,
Test2 = 1,
Test3 = Table1.Column2,
Test4 = Table1.Column5,
Test5 = Table1.Column6
FROM Table1
LEFT JOIN Table2 ON Table1.Column1 = Table2.Column1
INNER JOIN Table3 ON Table1.Column3 = Table3.Column3
WHERE Table3.Column4 IN (1,2,6)
Here's the Linq so far:
var TestQuery = Table1_Collection.Select(x => new
{
Test1 = Table1.Column1,
Test2 = 1,
Test3 = Table1.Column2,
Test4 = Table1.Column5,
Test5 = Table1.Column6
})
[joins go here]
.Where("where stuff goes here");
Any ideas? I'm not so much seeking assistance with the .Where as I am the joins. I'm not sure about the formatting with the method syntax.
Here you go:
var results = Table3_Collection
.Where(i => column4s.Contains(i.Column4))
.Join(Table1_Collection, i => i.Column3, i => i.Column3, (i, j) => j)
.Join(Table2_Collection, i => i.Column1, i => i.Column1, (i, j) => i)
.Distinct(comparer);
In your original SQL query you weren't using selecting any columns from Table2, so you could omit that join. I included it above, but please feel free to remove it.
Also, your C# example didn't have Distinct, but I included it for you as it was in your original SQL query, and is most likely your intent. And, please, don't forget to implement your own IEqualityComparer. Here is an example of one:
class Table1Comparer : IEqualityComparer<Table1>
{
public bool Equals(Table1 x, Table1 y)
{
return x.Column1 == y.Column1
&& x.Column2 == y.Column2
&& x.Column3 == y.Column3
&& x.Column4 == y.Column4
&& x.Column5 == y.Column5
&& x.Column6 == y.Column6;
}
public int GetHashCode(Table1 obj)
{
return obj.GetHashCode();
}
}
try this example, I hope you help
class Table1
{
public int Id1 { get; set; }
public string Column1 { get; set; }
}
class Table2
{
public int Id2 { get; set; }
public string Column2 { get; set; }
}
class Table3
{
public int Id3 { get; set; }
public string Column3 { get; set; }
}
static void Main(string[] args)
{
var table1 = new List<Table1>();
var table2 = new List<Table2>();
var table3 = new List<Table3>();
for (int i = 0; i < 10; i++)
{
table1.Add(new Table1 { Id1 = i, Column1 = "column1_table1_" + i });
table2.Add(new Table2 { Id2 = i, Column2 = "column2_table2_" + i });
table3.Add(new Table3 { Id3 = i, Column3 = "column3_table3_" + i });
}
var table1JoinTable2 = table1.Join(table2, t1 => t1.Id1, t2 => t2.Id2, (t1, t2) => new { Id = t1.Id1, Column1 = t1.Column1, Column2 = t2.Column2 } );
var table1JoinTable2JoinTable3 = table1JoinTable2.Join(table3, t12 => t12.Id, t3 => t3.Id3, (t12, t3) => new { Id = t12.Id, Column1 = t12.Column1, Column2 = t12.Column2, Column3 = t3.Column3 });
var result1 = table1JoinTable2JoinTable3.Single(t123 => t123.Id == 1);
Console.WriteLine("Id={0} C1={1} C2={2} C3={3}", result1.Id, result1.Column1, result1.Column2, result1.Column3);
// prints "Id=1 C1=column_table1_1 C2=column_table2_1 C3=column_table3_1"
}
Here is an example of your original SQL statement in LINQ query syntax.
List<int> vals = new List<int> {1,2,6};
var qry = from rec1 in Table1
join rec2 in Table2 on rec1.Column1 equals rec2.Column2 into ljT2
from rec2 in ljT2.DefaultIfEmpty() //Handle left join
join rec3 in Table3 on rec1.Column1 equals rec3.Column3
where vals.Contains(rec3.Column4)
select new {
Test1 = rec1.Column1,
Test2 = 1,
Test3 = rec2 == null?null:rec2.Column2, //Must allow for rec2 to be null
Test4 = rec3.Column5,
Test5 = rec3.Column6
}
qry = qry.Distinct();
First I want to say hello, I'm new to this site ;-)
My problem is to transform the following sql-query into a c# linq-query.
( I HAVE searched hard for an existing answer but I'm not able to combine the solution for
the joins on multiple conditions and the grouping / counting ! )
The sql-query :
DECLARE #datestart AS DATETIME
DECLARE #dateend AS DATETIME
SET #datestart = '01.04.2014'
SET #dateend = '30.04.2014'
SELECT md1.value AS [controller],md2.value AS [action], COUNT(md2.value) AS [accesscount], MAX(re.TIMESTAMP) AS [lastaccess] FROM recorderentries AS re
INNER JOIN messagedataentries AS md1 ON re.ID = md1.recorderentry_id AND md1.position = 0
INNER JOIN messagedataentries AS md2 ON re.ID = md2.recorderentry_id AND md2.position = 1
WHERE re.TIMESTAMP >= #datestart AND re.TIMESTAMP <= #dateend
AND re.messageid IN ('ID-01','ID-02' )
GROUP BY md1.value,md2.value
ORDER BY [accesscount] DESC
Any suggestions are welcome ...
What i have so far is this :
var _RecorderActionCalls = (from r in _DBContext.RecorderEntries
join m1 in _DBContext.MessageDataEntries on
new {
a = r.ID,
b = 0
} equals new {
a = m1.ID,
b = m1.Position
}
join m2 in _DBContext.MessageDataEntries on
new {
a = r.ID,
b = 0
} equals new {
a = m2.ID,
b = m2.Position
}
where r.TimeStamp >= StartDate & r.TimeStamp <= EndDate & (r.MessageID == "VAREC_100_01" | r.MessageID == "VAAUTH-100.01")
group r by new { md1 = m1.Value, md2 = m2.Value } into r1
select new { controller = r1.Key.md1, action = r1.Key.md2, count = r1.Key.md2.Count() }).ToList();
But this throws an exception ( translated from german ) :
DbExpressionBinding requires an input expression with a Listing Result Type ...
UPDATE : Back with headache ... ;-)
I found a solution to my problem :
var _RecorderActionCalls = _DBContext.RecorderEntries
.Where(r => r.TimeStamp >= StartDate & r.TimeStamp <= EndDate & (r.MessageID == "VAREC_100_01" | r.MessageID == "VAAUTH-100.01"))
.GroupBy(g => new { key1 = g.MessageData.FirstOrDefault(md1 => md1.Position == 0).Value, key2 = g.MessageData.FirstOrDefault(md2 => md2.Position == 1).Value })
.Select(s => new {
ControllerAction = s.Key.key1 + " - " + s.Key.key2,
Value = s.Count(),
Last = s.Max(d => d.TimeStamp)
}).ToList();
With this syntax it works for me. Thank you for thinking for me :-)
Something like that:
List<string> messageIdList = new List<string> { "ID-01", "ID-02" };
from re in RecorderEntries
from md1 in MessageDataEntries
from md2 in MessageDataEntries
where re.ID = md1.recorderEntry_id && md1.position == 0
where re.ID = md2.recorderEntry_id && md2.position == 1
where idList.Contains(re.messageid)
let joined = new { re, md1, md2 }
group joined by new { controller = joined.md1.value, action = joined.md2.value } into grouped
select new {
controller = grouped.Key.controller,
action = grouped.Key.action,
accesscount = grouped.Where(x => x.md2.value != null).Count(),
lastaccess = grouped.Max(x => x.re.TimeStamp) }