Linq to SQL latest date - sql

I have a linq to sql query
var items = from p in ctx.bam_Zending_AllInstances
join q in ctx.bam_Zending_CompletedRelationships
on p.ActivityID equals q.ActivityID
join r in ctx.bam_Prestatie_AllInstances
on q.ReferenceData equals r.ActivityID
where q.ReferenceType == "Activity" &&
p.Zendingnummer == zenderNr
orderby r.PrestatieCode
select new Data.BAMPrestatieInstance
{
Aanvaard = r.PrestatieAanvaard,
Contactnummer = r.ContactNr,
Foutmelding = r.Foutmelding,
Identificatie = r.Identificatie,
Ontvangen = r.PrestatieZendingOntvangen,
Uitvoerdatum = r.Uitvoerdatum,
ZendingsNr = p.Zendingnummer,
PrestatieCode = r.PrestatieCode
};
This returns a list of classes of multiple "r.PrestatieCode"s. "Uitvoerdatum" is a date however, and I need to only have the latest date for each r.PrestatieCode. How should I go about with this? Because I know how to do this in sql, but I can't seem to find the way to do it in linq.
Need this a lot atm actually,
any help is usefull,
thanks a bunch!
Gr

There is probably a more optimal way, but this will do what you want. With items defined as above:
var whatYouWant = items
.GroupBy(r => r.PrestatieCode)
.Select(
g => g.Single(
r => r.Uitvoerdatum == g.Max(s => s.Uitvoerdatum)
)
);
What this does: First it groups your result set by Data.BAMPrestatieInstance.PrestatieCode. Then, from each group with the same Data.BAMPrestatieInstance.PrestatieCode, it extracts the maximum Data.BAMPrestatieInstance.Uitvoerdatum and then finds the unique item with Data.BAMPrestatieInstance.Uitvoerdatum equal to that maximum date. If there is not a unique item with Data.BAMPrestatieInstance.Uitvoerdatum equal to that maximum date you can alter accordingly (use Where instead of Single, for example).
Let me know if I misunderstood your requirements.

If you know how to do it in SQL, you could write it like:
yourDataContext.ExecuteQuery<Data.BAMPrestatieInstance>(
"<sql query>");

Related

Convert SQL query to Linq (Need help to write sql query to linq)

This is my query returns me accurate result that I want. I want to write this in LINQ.
select i.reportdate,co.naam,i.issueid,i.vrijetekst,i.lockuser,te.teamnaam, count(ie.issueid) as events, sum(ie.bestedetijd) as Tijd
from company co,hoofdcontracten hc,subcontracten sc,sonderhoud so,g2issues i,g2issueevents ie, g2issuestatus iss,teams te,locatie l
Where co.companyid = hc.companyid And
hc.hcontractid = sc.hcontractid and
so.scontractid = sc.scontractid and
sc.scontractid = i.scontractid and
i.issueid = ie.issueid and
so.teamid = te.teamid and
ie.locatieid = l.locatieid and
l.bezoek = 0 and
i.issuestatusid = iss.issuestatusid and
fase < 7 and
co.companyid <> 165
group by i.reportdate,co.naam,i.issueid,i.vrijetekst,i.lockuser,te.teamnaam ,i.reportdate
having sum(ie.bestedetijd)>123
I am trying this but confused at select clause. How can I use aggregate function in select clause and group by clause also.
var myList = (from co in _context.Company
from hc in _context.Hoofdcontracten
from sc in _context.Subcontracten
from so in _context.Sonderhoud
from i in _context.G2issues
from ie in _context.G2issueEvents
from iss in _context.G2issueStatus
from te in _context.Teams
from l in _context.Locatie
where
co.CompanyId == hc.CompanyId
&& hc.HcontractId == sc.HcontractId
&& so.ScontractId == sc.ScontractId
&& sc.ScontractId == i.ScontractId
&& i.IssueId == ie.IssueId
&& so.Teamid == te.Teamid
&& ie.LocatieId == l.LocatieId
&& l.Bezoek == false
&& i.IssuestatusId == iss.IssueStatusId
&& iss.Fase < 7
&& co.CompanyId != 165
select new { }).ToList();
My! Someone was trying to save a few minutes typing time using all kinds of undecipherable variable names like hc, sc, so, i, ie, iss, without bothering that this would tenfold the time needed to understand what happens.
I haven't tried to decipher your query fully, apparently you thought it was not needed to show your entity framework classes and relation between them.
What I gather is that you want to perform a big join and then select several columns from the join. You want to group the resulting collection into groups of items that have the same reportdate, name, issueid, .... You want the bestede tijd on all items in each group, and you want the number of items in the group
LINQ has two types of syntaxes which in fact do the same: Query syntax and Method syntax. Although I can read the query syntax, I'm more familiar with the method syntax, so my answer will be using the method syntax. I guess you'll understand what happens.
I'll do it in smaller steps, you can concatenate all steps into one if you want.
First you do a big join, after which you select some columns. A big join is one of the few statements that are easier when written in query syntax (See SO: LINQ method syntax for multiple left join)
var bigJoin = from hc in _context.Hoofdcontracten
from sc in _context.Subcontracten
from so in _context.Sonderhoud
...
from l in _context.Locatie
where
co.CompanyId == hc.CompanyId
&& hc.HcontractId == sc.HcontractId
...
&& iss.Fase < 7
&& co.CompanyId != 165
select new
{
hc,
sc,
so,
... // etc select only items you'll use to create your end result
};
Now you've got a big table with the join results. You want to divide this table into groups with the same value for
{
i.reportdate,
co.naam,
i.issueid,
i.vrijetekst,
i.lockuser,
te.teamnaam,
}
(by the way: you mentioned reportdate twice in your GroupBy, I guess that's not what you meant)
This grouping is done using Enumerable.GroupBy.
var groups = bigjoin.GroupBy(joinedItem => new
{ // the items to group on: all elements in the group have the same values
ReportDate = i.Reportdate,
CompanyName = co.naam,
IssueId = i.issueid,
FreeText = i.vrijetekst,
LockUser = i.lockuser,
TeamName = te.teamnaam,
});
The result is a collection of groups. Each group contains the original bigJoin items that have the same value for for ReportDate, CompanyName, etc. This common value is in group.Key
Now from every group you want the following items:
Several of the common values in the group (ReportDate, CompanyName, IssueId, ...). We get them from the Key of the group
Tijd = the sum of ie.bestedeTijd of all elements in the group
Events = is the number of ie.IssueId of all elements in the group. As every element in the group has only one ie.IssueId, the result is also the number of elements in the group.
From this result, you only want to keep those with a Tijd > 123
So we'll do a new select on the groups, followed by a Where on Tijd
var result = groups.Select(group => new
{
Tijd = group.Sum(groupElement => groupElement.ie.bestedetijd),
Events = group.Count(),
// the other fields can be taken from the key
ReportDate = group.Key.reportdate,
CompanyName = group.Key.CompanyName,
IssueId = group.Key.Issueid,
FreeText = group.Key.FreeText,
LockUser = group.Key.LockUser,
TeamName = group.Key.TeamName,
})
.Where(resultItem => resultItem.Tijd > 123);

Slick function for SQL exists

I want to construct an SQL along this but try not to use sqlu.
select el.oid, el.name, el.res_cat from el
left join bk on (el.cat = bk.cat and bk.oid=100)
where not exists (select 1 from dates bd where
el.oid=bd.lots_oid and bd.bk_oid = bk.oid) and el.e_oid=bk.e_oid
Are there Slick functions for SQL exists or not exists? Thanks
Update 1
I realized my mistakes when I revisited my Slick code again. I want to apologize for the false alarm I set. This is not an answer and hopefully someone can help me to rectify my mistakes. For the time being, I am using Slick's plain SQL to continue my work.
The Slick query I constructed didn't work. It was close to the SQL I wanted. What I did was,
val elQuery = elTable.joinLeft(bkTable)
.on((el, bk) => el.cat === bk.cat && bk.oid === 100)
val query = for {
a <- elQuery if bdTable.filterNot(bd => a._2.map(_.oid === bd.bkOid).isDefined && a._1.oid === bd.elOid).exists
} yield a
finalQuery.result.statements.foreach(x => Logger.debug(s"xx => $x"))
I notice filterNot does not generate a SQL not exists. This is the other portion that lost me.
I don't have enough reputation to make comment yet. But I assume that you want to get all rows that doesn't exit in dates table. I would rewrite your query like below:
SELECT
el.oid, el.name, el.res_cat.cat
FROM
el
LEFT JOIN bk ON bk.cat = el.cat
AND bk.e_oid = el.e_oid
AND bk.oid = 100
LEFT JOIN dates bd ON bd.lots_oid = el.oid
AND bd.bk_oid = bk.oid
WHERE
bd.lots_oid IS NULL
Explanation:
Instead of taking NOT EXISTS, you can achieve the same thing by LEFT JOIN dates and specify on WHERE condition that the primary key (PK) for dates IS NULL. I don't know the PK for dates table, so I just add the column I know. You should adjust it to the PK of dates table.
LEFT JOINing and WHERE PK IS NULL ensures you that the row doesn't exist on the left joined table.

What am I doing wrong in this SQL to LINQ conversion?

I'm using LINQPad in my effort to convert SQL to LINQ and learn LINQ in the process. I'm running into some problems, though, and was hoping someone could look at my resulting LINQ code to see if I'm on the right track?
Here's my SQL code:
Select Count(Convert(varchar(250),
Comment.CommentId)) as Num,
DiscussionBoard.ItemName,
Status.Status,
Status.Sequence
From Comment inner join status on Comment.StatusID = Status.StatusID
inner join DiscussionBoard on Comment.DiscussionBoardID
= DiscussionBoard.DiscussionBoardID
WHERE discussionboard.DiscussionBoardID
= '3ab7c139-317c-4450-9823-45a40ea6d0ff'
Group By status.Status,
Status.Sequence,
DiscussionBoard.ItemName
ORDER BY Status ASC
Here is the LINQ code that I've come up with so far. Bear with me, I'm just now learning LINQ and I haven't quite got my head around it. Any pointers would be greatly appreciated:
from Comment in Comments
where DiscussionBoard.DiscussionBoardID == '3ab7c139-317c-4450-9823-45a40ea6d0ff'
join Status in Statuses on Comment.StatusID equals Statuses.StatusID
join DiscussionBoard in DiscussionBoards on Comment.DiscussionBoardID equals DiscucussionBoard.DiscussionBoardID
group CountGroup by new {
Status.Status,
Status.Sequence,
DiscussionBoard.DiscussionBoardID
}
select new
{
Count = CountGroup.Count(),
DiscussionBoard.ItemName,
Status.Status,
Status.Sequence
}
group x by y
This fragment ends a query.
I think you meant:
group x by y into z
This fragment continues the query with z in scope. and removes all prior range variables from scope. z is an IGrouping<y, x>, which is to say, the key type is y's type and the group element type is x's type.
Here's my stab at your query:
from comment in Comments
where comment.DiscussionBoard.DiscussionBoardID == '3ab7c139-317c-4450-9823-45a40ea6d0ff'
let status = comment.Status
let board = comment.DiscussionBoard
group comment by new {
status.Status,
status.Sequence,
board.ItemName
} into g
select new
{
Count = g.Count(),
ItemName = g.Key.ItemName,
Status = g.Key.Status,
Sequence = g.Key.Sequence
}
Another way to open this query would be:
from board in DiscussionBoards
where board.DiscussionBoardID == '3ab7c139-317c-4450-9823-45a40ea6d0ff'
from comment in board.Comments

Giving different record set after changing simple SQL query to LINQ query

I have write the below query in simple SQL,
I want to change it to use LINQ, I have tried, but my LINQ query and the original SQL statement are giving different record sets.
Simple SQL Query:
select *
from Paymentadvices
where status = 3
and Id in (select PaymentAdviceId from Approvals where ApprovedById = 13)
LINQ:
var myPaymentAdviceList = from pa in db.PaymentAdvices
where pa.Status == 3
join Ap in db.Approvals on pa.Id equals
Ap.PaymentAdviceId
where Ap.EmployeeId == 13
orderby pa.PaidDate descending
select pa;
I am not supposed to use join I guess, What should I use ?
var a = db.Approvals.Where( x => x.ApprovalById = 13).PaymentAdviceId;
var b = db.Paymentadvices.Where(x => x.status ==3 && a.Contains(x.Id);
.Contains() makes the WHERE IN () , you don't need a join there
var a = from a in db.Approvals
where a.ApprovedById == 3
select a.PaymentAdviceId;
var b = (from p in db.PaymentAdvices
where p.Status == 3 &&
a.Contains(p.Id)
select p).ToList();
those are both linq , the top is just lambda expressions which are commonly used in Linq queries. I would reccommend that you get used to reading/ writing both styles . The majority of code you'll come across in lambda style
I believe something like the below would work:
var query = from p in db.PaymentAdvices
where p.Status == 3 && db.Approvals
.Select(a => a.Id)
.Where(a => a.ApprovedById == 13)
.Contains(p.Id)
select p;
Though it's worth noting that #Scott Selby and #axrwkr solutions above are essentially the exact same thing in another form.

How can i do this SQL in Linq? (Left outer join w/ dates)

My LINQ isnt the best, neither is my SQL but im trying to do something like this in LINQ (its kind of in pseudo-code)
select * from CarePlan c
-- only newest Referral based on r.Date (if more than one exists)
left outer join Referral r on r.CarePlanId = c.CarePlanId
where c.PatientId = 'E4A1DA8B-F74D-4417-8AC7-B466E3B3FFD0'
The data looks like this:
A Patient can have a bunch of careplans
each careplan can have 0 to n referrals (I want the newest referral per careplan - if any exist)
Would like to return a list of careplans for each patient (whether or not they have a referral or not, if it has more than one referral - grab the newest one)
Thanks for any help guys
In LINQ you use the DefaultIfEmpty to achieve a left outer join - examples at http://msdn.microsoft.com/en-us/library/bb397895.aspx
Assuming that the referrals are not a (potentially empty) collection on the care plans so you're joining two collections together ...
Your query it would be something like:
Get the latest referral per Care Plan:
var latestReferrals = from r in referrals
group r by r.CarePlanId into lr
select new { CarePlanId = lr.Key, LatestReferral = lr.OrderByDescending(lrd => lrd.Date).First()};
Find the combined details:
var q = from c in CarePlan
where c.PatientId = 'E4A1DA8B-F74D-4417-8AC7-B466E3B3FFD0'
join lr in latestReferrals on c.CarePlanId equals lr.CarePlanId into gj
from subReferral in gj.DefaultIfEmpty()
select new { CarePlanId = c.CarePlanId, LatestReferral = (subReferral == null) ? null : subReferral.LatestReferral };
Depending on whether you want many referral properties or just a few you may or may not want the whole Referral object in the second part or just extract the relevant properties.
You may be able to combine these into a single query but for readability it may be easier to keep them separate. If there is a combined solution you should also compare performance of the two approaches.
EDIT: see comment for joining patients/other tables from care plans
If Patient is joined from Referral (as per comment) then its more complex because you're doing several left outer joins. So switching to the slightly more concise syntax:
var combined = from c in carePlans
where c.PatientId = 'E4A1DA8B-F74D-4417-8AC7-B466E3B3FFD0'
from lr in latestReferral.Where(r => r.CarePlanId == c.CarePlanId).DefaultIfEmpty()
from p in patients.Where(patient => patient.PatientId == ((lr != null) ? lr.LatestReferral.PatientId : -1)).DefaultIfEmpty()
select new { c.CarePlanId, PatientName = (p == null) ? "no patient" : p.PatientName, LatestReferral = (lr == null) ? null : lr.LatestReferral };