Unexpected database output when using INNER JOIN - c#

I have the following SQL query
SELECT
r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID,
ra.BEZEICHNUNG AS raumBEZEICHNUNG, ra.ID AS raumID
FROM
RAUM r
INNER JOIN RAZUORDNUNG rz ON rz.RAUM_ID = r.ID
INNER JOIN RAUMATTRIBUTE ra ON rz.RAUMATTRIBUTE_ID = ra.ID
WHERE
RAUMKLASSE_ID = ISNULL(#Raumklasse_ID, RAUMKLASSE_ID)
AND STADT_ID = ISNULL(#Stadt_ID, STADT_ID)
AND GEBAEUDE_ID = ISNULL(#Gebaeude_ID, GEBAEUDE_ID)
AND REGION_ID = ISNULL(#Region_ID, REGION_ID)
AND RAUMATTRIBUTE_ID = ISNULL(#Raumattribute_ID, RAUMATTRIBUTE_ID)
But I think that something is wrong with that.
For example:
If I put three in the RAUMKLASSE_ID textfield in the browser and invoke my method it returns only one room. But there are six rooms with that ID. The strange thing is, that if I remove the two INNER JOIN and the second line of my SELECT, like this:
SELECT
r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID
FROM
RAUM r
WHERE
RAUMKLASSE_ID = ISNULL(#Raumklasse_ID, RAUMKLASSE_ID)
AND STADT_ID = ISNULL(#Stadt_ID, STADT_ID)
AND GEBAEUDE_ID = ISNULL(#Gebaeude_ID, GEBAEUDE_ID)
AND REGION_ID = ISNULL(#Region_ID, REGION_ID)
AND RAUMATTRIBUTE_ID = ISNULL(#Raumattribute_ID, RAUMATTRIBUTE_ID)
it is returning the six rooms, which is correct. I don't know what the problem is with my query. Maybe someone can help me with that?
Thanks in advance

This is the expected behaviour, since:
FROM RAUM r
INNER JOIN RAZUORDNUNG rz ON rz.RAUM_ID = r.ID
INNER JOIN RAUMATTRIBUTE ra ON rz.RAUMATTRIBUTE_ID = ra.ID
Will get you only the rooms that are found in the tables RAUM, RAZUORDNUNG and RAUMATTRIBUTE tables, removing these INNER JOINs will get you all the rooms from the RAUM table that satisfy your condition, check these pages for more details about JOINs:
A visual explanation for JOINs.
Wikipedia article about JOINs

INNER JOIN won't return RAUM entries that have no corresponding RAZUORDNUNG or RAUMATTRIBUTE. You may need a LEFT JOIN instead; in this case, raumBEZEICHNUNG and raumID may be null in the returned set.

Related

How to handle linq join query when join on id is not available in the table c#

I am not trying to join my table using left outer join in LINQ where one of my join conditions does not satisfy. How can I still get the default record in my dataset? My SQL query runs perfectly fine but my join query is not returning the data.
Below is my SQL query where my left outer join works fine:
select
w.issueid as Issue
from worklog w
join jiraissue as j on w.issueid=j.ID
join issuetype AS ty ON ty.ID = j.issuetype
join project AS p on p.ID=j.PROJECT
left outer join customfieldvalue cfv on cfv.ISSUE = w.issueid
Below is my LINQ query in C# where if cfv.issue in the last join is not available in the table, I want to still return the default column.
var data = (from w in worklogs
join i in issuetypes on j.issuetype equals i.ID
join p in projects on j.PROJECT equals p.ID into table0
from c in table0.DefaultIfEmpty()
join cfv in customfieldvalues on w.issueid equals cfv.ISSUE into table1
from d in table1.DefaultIfEmpty()
{
IssueKey = l.Key.pkey + '-' + l.Key.issuenum,
Hours = l.Sum(w => w.timeworked)
}).ToList();
Any help is appreciated.
Thank you.

How to do a Linq Left Outer Join with a middle table?

I've been following a few examples from this website on how to create Linq Left Outer Join queries but I haven't found any examples of where the "outer key in the left join doesn't point to the inner key but instead points to a previous key". Bear with me for that phrasing I know it's not correct but have a look at the following snippets of code and maybe it will be clearer.
Specifically, see the first left join where sp.SalesPersonID = j.SalesPersonID.
select rt.Name as ResourceType, s.FirstName + ' ' + s.Surname as Supervisor, sp.FirstName + ' ' + sp.LastName as SalesPerson, tr.OrderCodeID, tr.SkillID
, j.CustomerName, j.JobNumber
from dbo.TaskResource tr join projects.Task t on t.ID = tr.taskiD
join dbo.ResourceType rt on rt.ID = tr.ResourceTypeID
join projects.projecttask pt on pt.taskid = tr.taskid
join projects.jobproject jp on jp.projectid = pt.projectid
join crm.tbljobs j on j.jobid = jp.jobid
left join common.tblSalesPersons sp on sp.SalesPersonID = j.SalesPersonID
left join common.tblSupervisors s on s.SupervisorID = j.SupervisorID
where JobDeleted is null or JobDeleted = 0
order by ResourceType
When converted to Linq it would make
...from j in temp1.DefaultIfEmpty()
join sp in dbc.tblSalesPersons on j.SalesPersonID equals sp.SalesPersonID into temp2
So far so good. But when I do the next left join I though it would just be the same thing but pointing to one of the previous keys as I mentioned earlier so instead of using the sp variable which I've seen several examples of, I use the j variable which is from a previous join:
from sp in temp2.DefaultIfEmpty()
join s in dbc.tblSupervisors on j.SupervisorID equals s.SupervisorID
Here is the full code snippet:
List<ResourceTreeObject> resourceTreeObjects = (
from tr in dbc.TaskResources
join t in dbc.Tasks on tr.TaskID equals t.ID
join rt in dbc.ResourceTypes on tr.ResourceTypeID equals rt.ID
join pt in dbc.ProjectTasks on tr.TaskID equals pt.TaskID
join jp in dbc.JobProjects on pt.ProjectID equals jp.ProjectID
join j in dbc.tblJobs on jp.JobID equals j.JobID into temp1
from j in temp1.DefaultIfEmpty()
join sp in dbc.tblSalesPersons on j.SalesPersonID equals sp.SalesPersonID into temp2
from sp in temp2.DefaultIfEmpty()
join s in dbc.tblSupervisors on j.SupervisorID equals s.SupervisorID
where j.JobDeleted == null || j.JobDeleted == 0
select new ResourceTreeObject
{
TaskResourceID = tr.ID
,
TaskID = tr.TaskID
,
ResourceTypeID = tr.ResourceTypeID
,
ResourceType = rt.Name
,
SkillID = tr.SkillID
,
OrderCodeID = tr.OrderCodeID
,
PermissionID = tr.PermissionID
,
JobID = j.JobID
,
JobNumber = j.JobNumber
,
CustomerName = j.CustomerName
,
Salesperson = sp.FirstName + " " + sp.LastName
,
Supervisor = s.FirstName + " " + s.Surname
}).ToList();
And this results in the wrong query. The last "left join" is treated like an inner join and returns the wrong number of rows. So in essence what I'm asking is, how do I (in LinQ) do two consecutive left outer joins after doing several consecutive inner joins but use the key from one of the previous tables in my left out join?
Also I'm not sure what the correct terminology for inner/outer keys etc. hence the awkward phrasing and title. Perhaps someone could correct that so it would be more beneficial to others. Thank you.
Your LINQ translation is just a little off.
The SQL has an inner join on crm.tbljobs followed by outer joins on common.tblSalesPerson and common.tblSupervisors.
The LINQ has outer joins on dbc.tblJobs and dbc.tblSalesPersons followed by an inner join on dbc.tblSupervisors.
into temp1 ... from j in in temp1.DefaultIfEmpty() makes the outer join happen on the table introduced prior to the into, which is dbc.tblJobs.
So it should be:
...
// inner join
join j in dbc.tblJobs on jp.JobID equals j.JobID
// left outer join
join sp in dbc.tblSalesPersons on j.SalesPersonID equals sp.SalesPersonID into salesPersons
from sp in salesPersons.DefaultIfEmpty()
// left outer join
join s in dbc.tblSupervisors on j.SupervisorID equals s.SupervisorID into supervisors
from s in supervisors.DefaultIfEmpty()
...
I changed temp1 and temp2 to more meaningful names to demonstrate what they represent in the outer join syntax. Note the relationship and relative position of dbc.tblSalesPersons to salesPersons, for example.
One more thing to remember is that sp and s can be null, so make sure you check for that before accessing their FirstName, LastName, and Surname properties.

LINQ Left Join with multiple ON OR conditions

I'm sorry for telling that I've a little bit weak on LINQ, I always do write SQL query before I start working on the complicated LINQ.
I want to ask that how to convert this SQL Query into LINQ with LEFT JOIN with multiple ON conditons with the OR operator.,
m.MerchandiseId will be use for twice in ON condition
SELECT
*
FROM
Inbox AS i
INNER JOIN [User] AS u ON i.FromUserId = u.UserId
LEFT OUTER JOIN Merchandise AS m ON
u.MerchandiseId = m.MerchandiseId
OR
i.ToMerchantId = m.MerchandiseId
WHERE
i.ToCompanyId = 10
OR
i.FromCompanyId = 10
var message = (from i in db.Inbox
join u in db.User on i.FromUserId equals u.UserId
join m in db.Merchandise on u.MerchandiseId equals m.MerchandiseId //here I want to ON i.MerchantId = m.MerchandiseId, but it doesn't allow
where i.ToCompanyId == user.CompanyId || i.FromCompanyId == user.CompanyId
orderby i.CreatedAt descending
group m.MerchandiseId by new { m.MerchandiseId, m.MerchandiseName } into grp
select new
{
MerchandiseId = grp.Key.MerchandiseId,
MerchandiseName = grp.Key.MerchandiseName,
InboxMessage = (from e in db.Inbox
join us in db.User on e.FromUserId equals us.UserId
join mer in db.Merchandise on us.MerchandiseId equals mer.MerchandiseId
where mer.MerchandiseId == grp.Key.MerchandiseId
orderby e.CreatedAt descending
select e.InboxMessage).FirstOrDefault(),
CreatedAt = (from e in db.Inbox
join us in db.User on e.FromUserId equals us.UserId
join mer in db.Merchandise on us.MerchandiseId equals mer.MerchandiseId
where mer.MerchandiseId == grp.Key.MerchandiseId
orderby e.CreatedAt descending
select e.CreatedAt).FirstOrDefault(),
}).ToList();
The bottom LINQ Query I've write for it. However, I just can work on the left join with multiple ON clause in LINQ. Appreciate if someone would help me on this. Thanks!
I don't believe Linq supports the use of the OR operator with multiple columns, but that said, I wouldn't use OR even in SQL as it makes the join's intention unclear and it also obscures where the data originated from - it also isn't immediately clear what happens if there are multiple matches for each column. Instead I would JOIN twice on the different columns and let the projection-clause handle it:
SELECT
*
FROM
Inbox
INNER JOIN [User] AS u ON i.FromUserId = u.UserId
LEFT OUTER JOIN Merchandise AS userMerchant ON u.MerchandiseId = userMerchant.MerchandiseId
LEFT OUTER JOIN Merchandise AS inboxMerchant ON Inbox.ToMerchantId = inboxMerchant .MerchandizeId
WHERE
Inbox.ToCompanyId = 10
OR
Inbox.FromCompanyId = 10
This can then be translated into Linq using the LEFT OUTER JOIN approach ( How to implement left join in JOIN Extension method )
Note that if you're using Entity Framework then you don't need to worry about doing any of this at all! Just use Include:
var query = db.Inbox
.Include( i => i.User )
.Include( i => i.User.Merchandise )
.Include i => i.Merchandise )
.Where( i => i.ToCompanyId = 10 || i.FromCompanyId == 10 );

LINQ: Inner join 2 table + outer join 1 table

I have 2 inner joins (3 tables) but I don't know and I find it hard to implement my research about outer join in LINQ. How do I change the last inner join to outer join, such that column will still join even if the column (Role) is null?
Here's an existing SQL version of this which I want to convert to LINQ:
SELECT dbo.EmployeeAccess.id, dbo.EmployeeAccess.EmpNo, dbo.EmployeeAccess.RoleID, dbo.EmployeeAccess.Active, dbo.EmployeeAccessLevel.Role,
dbo.View_HCM.LNameByFName
FROM dbo.EmployeeAccess LEFT OUTER JOIN
dbo.EmployeeAccessLevel ON dbo.EmployeeAccess.RoleID = dbo.EmployeeAccessLevel.id INNER JOIN
dbo.View_HCM ON dbo.EmployeeAccess.EmpNo = dbo.View_HCM.EmpNo
LINQ I now have with 2 inner joins:
(from ea in context.EmployeeAccesses
join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id
select new EmployeeWithEmail{
EmpNum = ea.EmpNo ?? 0,
EmailAddress = vh.EmailAddress,
LNameByFname = vh.LNameByFName,
Active2 = ea.Active ?? false
}).ToList();
}
Linq's outer join syntax uses 2 parts. First an into then DefaultIfEmpty
In your case, an outer join might look like this:
(from ea in context.EmployeeAccesses
join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id into outer_join
from subjoin in outer_join.DefaultIfEmpty()
select new EmployeeWithEmail{
EmpNum = ea.EmpNo ?? 0,
EmailAddress = vh.EmailAddress,
LNameByFname = vh.LNameByFName,
Active2 = ea.Active ?? false
}).ToList();
There are many tutorials on how to create the outer join in LINQ.

how to set the sql output unique? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Unexpected database output when using INNER JOIN
hello i have a sql query like this:
SELECT DISTINCT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID, ra.BEZEICHNUNG AS raumBEZEICHNUNG, ra.ID AS raumID
FROM RAZUORDNUNG rz
right join RAUMATTRIBUTE ra ON rz.RAUMATTRIBUTE_ID = ra.ID
right join RAUM r ON rz.RAUM_ID = r.ID
WHERE ....
i write the results in a list:
strasseObject.Add(new RAUM()
{
RaumName = rdr["BEZEICHNUNG"].ToString(),
RaumID = rdr["ID"].ToString(),
RaumAttribute = rdr["raumBEZEICHNUNG"].ToString(),
RaumAttributeID = rdr["raumID"].ToString()
});
and the output look like this
<RAUM>
<RaumName>Small Business Room</RaumName>
<RaumID>219</RaumID>
<RaumAttribute>A7OVERHEAD</RaumAttribute>
<RaumAttributeID>168876</RaumAttributeID>
</RAUM>
<RAUM>
<RaumName>Small Business Room</RaumName>
<RaumID>219</RaumID>
<RaumAttribute>Beamer</RaumAttribute>
<RaumAttributeID>168847</RaumAttributeID>
</RAUM>
</ArrayOfRAUM>
you can see that i get 2 results with the same "RaumName" but with different "Raumattribute". i want an output like this:
<RAUM>
<RaumName>Small Business Room</RaumName>
<RaumID>219</RaumID>
<RaumAttribute>A7OVERHEAD</RaumAttribute>
<RaumAttributeID>168876</RaumAttributeID>
<RaumAttribute>Beamer</RaumAttribute>
<RaumAttributeID>168847</RaumAttributeID>
</RAUM>
</ArrayOfRAUM>
thanks in advance
Have you tried to start the query on the other end (select from raum)?
SELECT DISTINCT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID, ra.BEZEICHNUNG AS raumBEZEICHNUNG, ra.ID AS raumID
FROM RAUM r
right join RAZUORDNUNG rz ON rz.RAUM_ID = r.ID
right join RAUMATTRIBUTE ra ON rz.RAUMATTRIBUTE_ID = ra.ID
WHERE ....
Remove rz.RAUMATTRIBUTE_ID column from your query, and than run.... like
SELECT DISTINCT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID, ra.BEZEICHNUNG AS raumBEZEICHNUNG, ra.ID AS raumID
FROM RAZUORDNUNG rz
right join RAUMATTRIBUTE ra ON rz.RAUMATTRIBUTE_ID = ra.ID
right join RAUM r ON rz.RAUM_ID = r.ID
WHERE ....
Distinct: The DISTINCT keyword can be used to return only distinct (different) values. So, RAUMATTRIBUTE_ID has different values that's why it return 2 rows.

Categories