Massive SQL query requires conversion to LINQ - sql

I have an SQL query which I need to convert to LINQ. have spent a whole day on it, didn't have much luck tough. Here's the query
SELECT PC.PRSCLAIMID,
date_format(PC.DATEOFCLAIM, '%d/%m/%Y') as DateofClaim,
PC.PRSREFNO,
PC.FKARTISTID,
PC.FKSETLISTINFOID,
PC.STATUS,
PC.FROMDNN,
PC.EXPORTTYPE,
PC.FK_CATEGORYID,
A.LOGINNAME,
A.BANDNAME,
SMCATEGORIESTYPE.CATEGORYTYPE,
Count(SMLIVECLAIMS.LIVECLAIMSID) AS GIGCOUNT,
SMCATEGORIES.ID AS PROCESSEDID,
SMCATEGORIES.CATEGORY,
Ifnull(BC.FILENAME, '') AS BULKCLAIM_NAME
FROM SMARTISTDETAILS AS A
INNER JOIN SMPRSCLAIMS AS PC
ON A.ARTISTID = PC.FKARTISTID
INNER JOIN SMCATEGORIES
ON PC.FK_CATEGORYID = SMCATEGORIES.ID
INNER JOIN SMCATEGORIESTYPE
ON SMCATEGORIES.FK_CATEGORYTYPEID = SMCATEGORIESTYPE.ID
INNER JOIN SMPRSLIVECLAIMLINK
ON PC.PRSCLAIMID = SMPRSLIVECLAIMLINK.FKPRSCLAIMID
INNER JOIN SMLIVECLAIMS
ON SMPRSLIVECLAIMLINK.FKLIVECLAIMID = SMLIVECLAIMS.LIVECLAIMSID
LEFT OUTER JOIN BULKCLAIMDETAIL BCD
ON BCD.FKPRSCLAIMID = PC.PRSCLAIMID
LEFT OUTER JOIN BULKCLAIM BC
ON BC.ID_BULKCLAIM = BCD.ID_BULKCLAIM
WHERE ( PC.EXPORTTYPE > 0 )
AND ( A.DBID = 1 )
AND ( CASE
WHEN PC.EXPORTTYPE = 1
AND ( SMLIVECLAIMS.GIGDATE < Date_add(Now(), INTERVAL -1 YEAR) ) THEN 0
ELSE 1
END = 1 )
GROUP BY PC.PRSCLAIMID
ORDER BY PC.DATEOFCLAIM DESC
what I did was the following conversion
from e in
(from artistData in dbContext.smartistdetails where artistData.DbId == 1 // SessionFacade.DBId
join smprsclaimsData in dbContext.smprsclaims on artistData.ArtistID equals smprsclaimsData.fkArtistID join smCategoriesData in dbContext.smcategories on smprsclaimsData.FK_CategoryID equals smCategoriesData.Id join smCategoriesTypeData in dbContext.smcategoriestype on smCategoriesData.fk_CategoryTypeId equals smCategoriesTypeData.Id join smPrsLiveClaimsLinkData in dbContext.smprsliveclaimlink on smprsclaimsData.PRSClaimID equals smPrsLiveClaimsLinkData.fkPRSClaimID join smLiveClaimData in dbContext.smliveclaims on smPrsLiveClaimsLinkData.fkLiveClaimID equals smLiveClaimData.LiveclaimsID join bulkClaimDetailData in dbContext.bulkclaimdetail on smprsclaimsData.PRSClaimID equals bulkClaimDetailData.fkPRSClaimID into bulkClaimDetailJoined from bulkClaimDetailJoinedData in bulkClaimDetailJoined.DefaultIfEmpty() join bulkClaimData in dbContext.bulkclaim on bulkClaimDetailJoinedData.ID_BulkClaim equals bulkClaimData.ID_BulkClaim into bulkClaimJoined from bulkClaimJoinedData in bulkClaimJoined.DefaultIfEmpty() where smprsclaimsData.ExportType > 0 select new {
PRSCLAIMID_Inner = smprsclaimsData.PRSClaimID,
GigDate = smLiveClaimData.GigDate,
DateofClaim = smprsclaimsData.DateofClaim,
PRSREFNO = smprsclaimsData.PRSRefNo,
FKARTISTID = smprsclaimsData.fkArtistID,
FKSETLISTINFOID = smprsclaimsData.fkSetlistInfoID,
STATUS = smprsclaimsData.Status,
FROMDNN = smprsclaimsData.FromDNN,
EXPORTTYPE = smprsclaimsData.ExportType,
FK_CATEGORYID = smprsclaimsData.FK_CategoryID,
LOGINNAME = artistData.LoginName,
BANDNAME = artistData.BandName,
CATEGORYTYPE = smCategoriesTypeData.CategoryType,
LiveclaimsID = smLiveClaimData.LiveclaimsID,
PROCESSEDID = smCategoriesData.Id,
CATEGORY = smCategoriesData.Category,
BULKCLAIM_NAME = bulkClaimJoinedData.FileName == null ? "" : bulkClaimJoinedData.FileName
})
where!(e.EXPORTTYPE == 1 && e.GigDate < oneYearOldDate)
group e by e.PRSCLAIMID_Inner into groupedData
select new {
PRSCLAIMID_Outer = groupedData.Key,
GIGCOUNT = groupedData.Count(),
DateofClaim = groupedData.Select(a = > a.DateofClaim).FirstOrDefault(),
PRSREFNO = groupedData.Select(a = > a.PRSREFNO).FirstOrDefault(),
FKARTISTID = groupedData.Select(a = > a.FKARTISTID).FirstOrDefault(),
FKSETLISTINFOID = groupedData.Select(a = > a.FKSETLISTINFOID).FirstOrDefault(),
STATUS = groupedData.Select(a = > a.STATUS).FirstOrDefault(),
FROMDNN = groupedData.Select(a = > a.FROMDNN).FirstOrDefault(),
EXPORTTYPE = groupedData.Select(a = > a.EXPORTTYPE).FirstOrDefault(),
FK_CATEGORYID = groupedData.Select(a = > a.FK_CATEGORYID).FirstOrDefault(),
LOGINNAME = groupedData.Select(a = > a.LOGINNAME).FirstOrDefault(),
BANDNAME = groupedData.Select(a = > a.BANDNAME).FirstOrDefault(),
CATEGORYTYPE = groupedData.Select(a = > a.CATEGORYTYPE).FirstOrDefault(),
PROCESSEDID = groupedData.Select(a = > a.PROCESSEDID).FirstOrDefault(),
CATEGORY = groupedData.Select(a = > a.CATEGORY).FirstOrDefault(),
BULKCLAIM_NAME = groupedData.Select(a = > a.BULKCLAIM_NAME).FirstOrDefault()
}).OrderByDescending(a = > a.DateofClaim)
this conversion is working but it is too slow, then I create another conversion
from smprsclaimsData in dbContext.smprsclaims
group smprsclaimsData by new { smprsclaimsData.PRSClaimID, smprsclaimsData.fkArtistID, smprsclaimsData.FK_CategoryID } into smprsclaimsGroupedData
join artistData in dbContext.smartistdetails on smprsclaimsGroupedData.Key.fkArtistID equals artistData.ArtistID
let loginName = artistData.LoginName
let bandName = artistData.BandName
join smCategoriesData in dbContext.smcategories on smprsclaimsGroupedData.Key.FK_CategoryID equals smCategoriesData.Id
join smCategoriesTypeData in dbContext.smcategoriestype on smCategoriesData.fk_CategoryTypeId equals smCategoriesTypeData.Id
join smPrsLiveClaimsLinkData in dbContext.smprsliveclaimlink on smprsclaimsGroupedData.Key.PRSClaimID equals smPrsLiveClaimsLinkData.fkPRSClaimID
join smLiveClaimData in dbContext.smliveclaims on smPrsLiveClaimsLinkData.fkLiveClaimID equals smLiveClaimData.LiveclaimsID
join bulkClaimDetailData in dbContext.bulkclaimdetail on smprsclaimsGroupedData.Key.PRSClaimID equals bulkClaimDetailData.fkPRSClaimID into bulkClaimDetailJoined
from bulkClaimDetailJoinedData in bulkClaimDetailJoined.DefaultIfEmpty()
join bulkClaimData in dbContext.bulkclaim on bulkClaimDetailJoinedData.ID_BulkClaim equals bulkClaimData.ID_BulkClaim into bulkClaimJoined
from bulkClaimJoinedData in bulkClaimJoined.DefaultIfEmpty()
where smprsclaimsGroupedData.Select(a => a.ExportType).FirstOrDefault() > 0 && artistData.DbId == 1
&& !(smprsclaimsGroupedData.Select(a => a.ExportType).FirstOrDefault() == 1 && smLiveClaimData.GigDate < oneYearOldDate)
select new
{
PRSCLAIMID_Inner = 1,
GigDate = smLiveClaimData.GigDate,
DateofClaim = smprsclaimsGroupedData.Select(a => a.DateofClaim),
PRSREFNO = smprsclaimsGroupedData.Select(a => a.PRSRefNo),
FKARTISTID = smprsclaimsGroupedData.Select(a => a.fkArtistID),
FKSETLISTINFOID = smprsclaimsGroupedData.Select(a => a.fkSetlistInfoID),
STATUS = smprsclaimsGroupedData.Select(a => a.Status),
FROMDNN = smprsclaimsGroupedData.Select(a => a.FromDNN),
EXPORTTYPE = smprsclaimsGroupedData.Select(a => a.ExportType),
FK_CATEGORYID = smprsclaimsGroupedData.Select(a => a.FK_CategoryID),
LOGINNAME = loginName,
BANDNAME = bandName,
CATEGORYTYPE = smCategoriesTypeData.CategoryType,
//GIGCOUNT = smprsclaimsGroupedData.Count(),
PROCESSEDID = smCategoriesData.Id,
CATEGORY = smCategoriesData.Category,
BULKCLAIM_NAME = bulkClaimJoinedData.FileName == null ? "" : bulkClaimJoinedData.FileName,
})
well this query is not fetching the expected data, i think it is due to multiple (group by)'s. I cannot post my DB Schema as well, the question is already too long to read. Any help or any suggestions on how to get around or work around this conversion.

I think you are over thinking the LINQ a little, try the following LINQ. The only thing I am not 100% sure about is the GIGCOUNT results so that might take a bit of fiddling with.
(
from A in SMARTISTDETAILS
join PC in SMPRSCLAIMS on A.ARTISTID equals PC.FKARTISTID
join categories in SMCATEGORIES on PC.FK_CATEGORYID equals categories.ID
join categoryType in SMCATEGORIESTYPE on categories.FK_CATEGORYTYPEID equals categoryType.ID
join link in SMPRSLIVECLAIMLINK on PC.PRSCLAIMID equals link.FKPRSCLAIMID
join liveClaims in SMLIVECLAIMS on link.FKLIVECLAIMID equals liveClaims.LIVECLAIMSID
join bulkDetail in BULKCLAIMDETAIL on PC.PRSCLAIMID equals bulkDetail.FKPRSCLAIMID into BULK_DETAILS
from BCD in BULK_DETAILS.DefaultIfEmpty()
join bulkClaim in BULKCLAIM on BCD.ID_BULKCLAIM equals bulkClaim.ID_BULKCLAIM into BULK_CLAIMS
from BC in BULK_CLAIMS.DefaultIfEmpty()
where
( PC.EXPORTTYPE > 0 )
&& ( A.DBID == 1 )
&& (
PC.EXPORTTYPE == 1 && liveClaims.GIGDATE < DateTime.Now.AddYears(-1) ? 0 : 1
) == 1
orderby PC.DATEOFCLAIM descending
select new
{
PC.PRSCLAIMID,
DateofClaim = PC.DATEOFCLAIM,
PC.PRSREFNO,
PC.FKARTISTID,
PC.FKLISTINFOID,
PC.STATUS,
PC.FROMDNN,
PC.EXPORTTYPE,
PC.FK_CATEGORYID,
A.LOGINNAME,
A.BANDNAME,
categoryType.CATEGORYTYPE,
// This gets me the correct count now
GIGCOUNT = SMPRSLIVECLAIMLINK.Where(LINK => LINK.FKPRSCLAIMID == PC.PRSCLAIMID && (PC.EXPORTTYPE == 1 && LINK.FKLIVECLAIMIDSMLIVECLAIMS.GIGDATE < DateTime.Now.AddYears(-1) ? 0 : 1) == 1).Count(),
PROCESSEDID = categories.ID,
categories.CATEGORY,
BULKCLAIM_NAME = BC.FILENAME ?? String.Empty
})
// Use distinct to get rid of duplicate rows
.Distinct()
.ToList()
.GroupBy(o =>
o.PRSCLAIMID
)
EDIT:
I changed how I calculate the GIGCOUNT property, this should now return the correct number. You will also want to use the Distinct() extension so that duplicate rows are removed.

Related

Database query - unusual query

I'm trying to transfer a query to LINQ
It's a bit complicated and I don't know if I'm doing the right thing
There is also a problem with SELECT to save it properly
SQL QUERY:
SELECT ISNULL(SUM(1),0) TotalSubmitted,
ISNULL(SUM(CASE WHEN Pic.PhotoFileName IS NULL THEN 0 ELSE 1 END),0) TotalAssigned
FROM tblFromPhone Ph
INNER JOIN tblOfficer O ON Ph.OfficerCode = O.Code
OUTER APPLY(SELECT PhotoFileName FROM tblPhotos P
WHERE P.validityTo IS NULL
AND P.PhotoFileName = Ph.DocName
AND P.OfficerID = O.OfficerID)Pic
WHERE CAST(Ph.LandedDate AS DATE) BETWEEN #FromDate AND #ToDate
AND O.ValidityTo IS NULL
AND DocType = N'E'
AND OfficerCode = #OfficerCode
My LINQ:
var res = (from FP in context.TblFromPhone
join O in context.TblOfficer on FP.OfficerCode equals O.Code
join P in context.TblPhotos on FP.DocName equals P.PhotoFileName into P
from Ph in P.Where(x => x.OfficerId == O.OfficerId).DefaultIfEmpty()
where Ph.ValidityTo == null
where FP.LandedDate >= DateTime.Parse(fromDate)
&& FP.LandedDate <= DateTime.Parse(toDate)
&& O.ValidityTo == null
&& FP.DocType == "E"
&& FP.OfficerCode == officerCode
select new EnrolmentModel()
{
TotalSubmitted = // How to make?
TotalAssigned = // How to make?
})
.FirstOrDefault();

SQL to Entity Framework query for distinct instances

I need to translate the following query from SQL into an Entity Framework query. Can anyone please help.
var query3 = string.Format(#"
SELECT DISTINCT
Boxes.BoxName,
Employees.EmployeeNumber,
Boxes.Port,
Boxes.SerialNumber
FROM
Eventlog
INNER JOIN Boxes
ON Eventlog.SerialNumber = Boxes.SerialNumber
INNER JOIN Employees
ON Eventlog.EmployeeId = Employees.EmployeeId
WHERE
ActionId = {4}
AND Boxes.Deactivated = 0
AND ( ('*' = '{0}')
OR (Boxes.SerialNumber = '{0}') )
AND ( (-1 = {1})
OR (Employees.EmployeeId = '{1}') )
AND EventTime >= '{2}'
AND EventTime <= '{3}'
", boxFilter3, ReportEmployeeIdFilter, ReportStartDate, ReportEndDate, actionFilter);
Something like this should work:
var query = (from log in context.Eventlog
join box in context.Boxes
on log.SerialNumber equals box.SerialNumber
join employee in context.Employees
on log.EmployeeId equals employee.EmployeeId
where log.ActionId == actionFilter
&& box.Deactivated == 0
&& (boxFilter3 == "*" || box.SerialNumber == boxFilter3)
&& (ReportEmployeeIdFilter == -1 || employee.EmployeeId == ReportEmployeeIdFilter)
&& log.EventTime >= ReportStartDate
&& log.EventTime <= ReportEndDate
select new
{
box.BoxName,
employee.EmployeeNumber,
box.Port,
box.SerialNumber
})
.Distinct();

LINQ - Left Outer Join with multiple parameters in Where clause

How can I do this SQL query in LINQ:
select * from chat c
left outer join lead s on c.key = s.id
where (typeId = 5 AND c.key = #clientId) OR (c.typeId = 4 AND s.clientId = #clientId)
Or this SQL query -- Same, same
select * from chat c
where (typeId = 5 AND c.key = #clientId) OR (typeId = 4 AND c.key in (select id from lead where clientId = #clientId))
What I have:
var chatter = (from chat in linq.Chat
join lead in linq.Lead
on chat.key equals lead.Id.ToString() into clientLeads
from cl in clientLeads.Where(l => l.clientId == clientId).DefaultIfEmpty()
where (chat.typeId == 5 && chat.key == clientId.ToString()) ||
(chat.typeId == 4 && chat.key == cl.Id.ToString())
select chat).WithPath(prefetchPath).OrderByDescending(c => c.CreatedDate);
The above LINQ query doesn't yeild any results from the latter WHERE clause, what am I missing?
I translated the second query to linq:
var leadIds = linq.Lead.Where(l => l.clientId == clientId.ToString()).Select(l => l.id);
var chatter = from chat in linq.Chat
where (chat.typeId == 5 && chat.key == clientId.ToString()) ||
(chat.typeId == 4 && leadIds.Contains(chat.key));

INNER JOIN LEFT JOIN in LINQ to SQL

How to convert INNER JOIN and LEFT JOIN in the following SQL query to LINQ to SQL? Thanks!
SELECT transactions.postdate,
transactions.clientkey AS TransClientKey,
transactions.type AS TransType,
clients.clientno,
Isnull(clients.nostmt, 0) AS CliNoStmt,
Isnull(aging.nostmt, 0) AS AgeNoStmt,
pmtchecks.*
FROM ((pmtchecks
INNER JOIN transactions
ON pmtchecks.transkey = transactions.transkey)
INNER JOIN clients
ON transactions.clientkey = clients.clientkey)
LEFT JOIN aging
ON ( transactions.clientkey = aging.clientkey )
AND ( pmtchecks.debtorkey = aging.debtorkey )
WHERE ( pmtchecks.debtorkey = 36927 )
AND ( transactions.status = 0 )
AND ( transactions.postdate <= '31-May-2012' )
AND ( ( transactions.postdate >= '01-May-2012' )
OR ( clients.clientno = 'UNKNOWN' ) )
ORDER BY pmtchecks.checkdate,
pmtchecks.checkno
Hi this is kind of dummy code i cnt say its exactly right but the idea will be exactly same to get the result
var anonymousType= (from pm in pmtchecks
join tr in transactions
on pm.transkey equals tr.transkey //INNERJOIN
join cl in clients
on tr.clientKey equals cl.clientKey
join ag in aging
on pm.debtorkey equals ag.debtorKey into ljoin //Left Join
from lj in ljoin.DefaultOrEmpty()
where pm.debortkey==36927 && tr.status==0 && tr.postdate<="31-May-2012" && tr.postdate>="01-May-2012" //u will have to change this to date format first
Select new {PostDate=tr.postdate, TransClientKey=tr.clientkey,TransType=tr.type,ClientNo=cl.clientno,CliNoStmt=cl.nomst ?? 0,AgeNoStmt=ag.nomst ??0,Pmtchecks=pm } //Anonymous type from this you can extract the values and fill to your custom type
).OrderBy(o=>o.Pmtchecks.checkdate).OrderBy(o=>o.Pmtchecks.checkno).ToList();
Hope this will help.
LINQ Query Samples
EDITED
var pmtchecks = from p in urcontext.pmtchecks
join t in urcontext.transactions on p.transkey equals t.transkey
join a in urcontext.aging on t.clientkey equals a.clientkey into details
from d in details.Where( a => ( a.debtorkey == p.debtorkey)).DefaultIfEmpty()
where (p.debtorkey == 36927 && t.status == 0 && t.postdate <= '31-May-2012'
&& (t.postdate >= '01-May-2012' || c.clientno == 'UNKNOWN' ))
orderby p.checkdate, p.checkno
select new
{
t.postdate,
t.clientkey,
// TransClientKey = t.clientkey, //only works if TransClientKey is property
t.type ,
//TransTypet = t.type ,//property
c.clientno,
c.nostmt,
//CliNoStmt = c.nostmt ?? 0,//property
a.nostmt//,
//AgeNoStmt = nostmt ?? 0,//property
//p. ... //follow above for p columns
};

Linq to SQL query taking forever

Ok, first I thought I had a problem with how I was querying things. But apparently the problem lies in how linq translates my query to sql.
Here's my linq:
var items = (from p in ctx.bam_Prestatie_AllInstances
join q in ctx.bam_Zending_AllRelationships on p.ActivityID equals q.ReferenceData
join r in ctx.bam_Zending_AllInstances on q.ActivityID equals r.ActivityID
orderby p.LastModified descending
where r.PrestatieOntvangen >= vanaf && r.PrestatieOntvangen <= tm
select new Data.BAMPrestatieInstance
{
Aanvaard = p.PrestatieAanvaard,
Contactnummer = r.ContactNr,
Identificatie = p.Identificatie,
Foutmelding = ((p.Foutmelding == "" || p.Foutmelding == null) && p.PrestatieAanvaard == null) ? "De prestatie is bezig met verwerkt te worden." : p.Foutmelding.Replace("\r\n", " "),
Ontvangen = p.PrestatieZendingOntvangen,
Uitvoerdatum = p.Uitvoerdatum.Replace('-', '/'),
Zender = r.Zender,
PrestatieCode = p.PrestatieCode,
ZendingsNr = r.Zendingnummer.ToString(),
GroepsAanvaarding = r.Identificatie
}).Take(100);
Which gets translated in:
SELECT TOP (100) [t3].[Zender], [t3].[ContactNr] AS [Contactnummer], [t3].[Identificatie], [t3].[value] AS [Uitvoerdatum], [t3].[PrestatieZendingOntvangen] AS [Ontvangen], [t3].[PrestatieAanvaard] AS [Aanvaard], [t3].[value2] AS [Foutmelding], [t3].[PrestatieCode], [t3].[value3] AS [ZendingsNr], [t3].[Identificatie2] AS [GroepsAanvaarding]
FROM (
SELECT [t2].[Zender], [t2].[ContactNr], [t0].[Identificatie], REPLACE([t0].[Uitvoerdatum], #p0, #p1) AS [value], [t0].[PrestatieZendingOntvangen], [t0].[PrestatieAanvaard],
(CASE
WHEN (([t0].[Foutmelding] = #p2) OR ([t0].[Foutmelding] IS NULL)) AND ([t0].[PrestatieAanvaard] IS NULL) THEN CONVERT(NVarChar(3800),#p3)
ELSE REPLACE([t0].[Foutmelding], #p4, #p5)
END) AS [value2], [t0].[PrestatieCode], CONVERT(NVarChar,[t2].[Zendingnummer]) AS [value3], [t2].[Identificatie] AS [Identificatie2], [t2].[PrestatieOntvangen], [t0].[LastModified]
FROM [dbo].[bam_Prestatie_AllInstances] AS [t0]
INNER JOIN [dbo].[bam_Zending_AllRelationships] AS [t1] ON [t0].[ActivityID] = [t1].[ReferenceData]
INNER JOIN [dbo].[bam_Zending_AllInstances] AS [t2] ON [t1].[ActivityID] = [t2].[ActivityID]
) AS [t3]
WHERE ([t3].[PrestatieOntvangen] >= #p6) AND ([t3].[PrestatieOntvangen] <= #p7)
ORDER BY [t3].[LastModified] DESC
As you can see, first it selects EVERYTHING and then it takes the top 100 and does the where. Why is this? Why can't it directly do the top 100, I think the problem why my queries run so long is because of this. Is there a better way to construct my linq query then?
Thanks
Try this:
var items = from p in ctx.bam_Prestatie_AllInstances.OrderByDesc(p => p.LastModified).Take(100)
join q in ctx.bam_Zending_AllRelationships on p.ActivityID equals q.ReferenceData
join r in ctx.bam_Zending_AllInstances on q.ActivityID equals r.ActivityID
where r.PrestatieOntvangen >= vanaf && r.PrestatieOntvangen <= tm
select new Data.BAMPrestatieInstance
{
Aanvaard = p.PrestatieAanvaard,
Contactnummer = r.ContactNr,
Identificatie = p.Identificatie,
Foutmelding = ((p.Foutmelding == "" || p.Foutmelding == null) && p.PrestatieAanvaard == null) ? "De prestatie is bezig met verwerkt te worden." : p.Foutmelding.Replace("\r\n", " "),
Ontvangen = p.PrestatieZendingOntvangen,
Uitvoerdatum = p.Uitvoerdatum.Replace('-', '/'),
Zender = r.Zender,
PrestatieCode = p.PrestatieCode,
ZendingsNr = r.Zendingnummer.ToString(),
GroepsAanvaarding = r.Identificatie
};
Since the sort applies only to your first table, I'd try to force the order by and take 100 to be applied before the join.