About the proper use of INNER JOIN - c#

I've been having problems trying to retrieve data from my database to a DataTable in Microsoft Visual C#. I've been told it's because of improper use of INNER JOINs. The query (Fill method) is the one that follows.
SELECT Bordero.id AS id, Titulo.id AS id_titulo, Titulo.valor AS valor_titulo,
Sacado.nome AS nome_sacado, Cliente.nome AS nome_cliente, Sacado.documento,
Titulo.taxa_adm AS taxa_adm_titulo, Titulo.desagio AS desagio_titulo,
Titulo.liquido AS liquido_titulo,
(CASE Titulo.tipo
WHEN 'True' THEN 'Cheque'
ELSE 'Duplicata'
END) AS tipo, Titulo.dias, Titulo.codigo, Titulo.vencimento,
Titulo.data_base, Bordero.desagio AS desagio_bordero,
Bordero.taxa_adm AS taxa_adm_bordero, Bordero.liquido AS liquido_bordero,
Bordero.bruto, Bordero.duplicata, Bordero.desconto, Bordero.iss, Bordero.iof,
Bordero.cpmf, Bordero.pis, Bordero.cofins, Desconto.valor AS valor_desconto,
Desconto.descricao, Bordero.id_cliente
FROM Bordero
INNER JOIN Cliente ON Bordero.id_cliente = Cliente.id
INNER JOIN Titulo ON Bordero.id = Titulo.bordero_id
INNER JOIN Sacado ON Sacado.id = Titulo.sacado_id
INNER JOIN Desconto ON Cliente.id = Desconto.id_cliente
The database diagram looks like this:
http://i53.tinypic.com/t0g4qp.jpg
Any hints on what's wrong?

Without stating what your problem is that you're experiencing my guess would be that you may need to be using LEFT OUTER JOIN for some of the tables instead of all INNER JOIN.
When using an INNER JOIN in a query, the data that you're matching via the ON clause must be not null in both tables. Meaning that if the ID exists on the left table (the one in the FROM clause) there must be a matching record in the right table (the one you're joining in via the INNER JOIN). If the right table does not have a matching record, the entire result is dropped from the query.
By using a LEFT OUTER JOIN instead, you allow the right table to return NULL instead for each data row that doesn't match.
TABLE A TABLE B
ID | Name ID | Address
1 | Alice 1 | 123 ABC St.
2 | Bob 3 | 789 XYZ St.
3 | Cam
Using the above tables, if you were to do an FROM A INNER JOIN B ON A.ID = B.ID only rows 1 and 3 would be returned. If you were to do a FROM A LEFT OUTER JOIN B ON A.ID = B.ID all rows from A would be returned and B.Address would be null for #2.

Related

How to Select all records from table 1 and exclude matching records from table 2 using LINQ

I want to select all records from table 1 and if there any match between table 1 and table 2 then I have to exclude that records.
Note: The requirement is I have to use left outer join for that..
For example,
table 1 table 2
1 1
2 2
3
Output should be 3
I have written query in SQL but I want this in SQL LINQ like from a in dbContext.Table1....
select t1.*
from table1 t1
left outer join table2 t2 on t1.ID = t2.ID and t1.Code = t2.Code
where s.ID is null
How to solve this?
var result = (from primer in one
join primer2 in two on primer.id equals primer2.id into gj
where gj.Count()==0
select new
{
primer.id
}).ToList();
Where ONE - it is first table, TWO - it is second table.
Instead of
...select new
{
primer.id
}...
You can use
...
select primer
...

LINQ Null Join with Pivot Table

I'm trying to get a list of servers thay may or may not belong to 1 or more groups to display in a grid.
Example
ServerID IP GroupID
1 192.168.1.44 1
1 192.168.1.44 10
2 192.168.1.45 1
3 192.168.1.46 2
4 192.168.1.47 null
5 192.168.1.48 null
If I have no records In the GroupServer Table. (Since there is no groups or groups exist but they are not assigned) I expect to get something like this:
ServerID IP GroupID
1 192.168.1.44 null
2 192.168.1.45 null
3 192.168.1.46 null
4 192.168.1.47 null
5 192.168.1.48 null
Since is a Many-to-Many relationship. I have
Group Table
Server Table
GroupServer Table
I could not find a LINQ Pivot Table example.
So I tried to buid my own.
var query = (from sg in context.ServerGroups
join servers in context.Servers on sg.ServerID equals servers.ID
join groups in context.Groups on sg.GroupID equals groups.ID
into serverxgroup
from gAddrBilling in serverxgroup.DefaultIfEmpty()
select new
{
ServerID = sg.ServerID,
ServerIP = server.IP,
GroupID = sg.GroupID
});
The Query above does not retrieve anything
And I quiet dont understand what the "from gAddrBilling" is for. Since I modify a snippet I was trying to make work. So I wonder if someone has already faced a problem like this and give me some hint, snippet or advice about what is what I'm missing.
Thank you.
First, this is not a pivot query, but a regular query on many-to-may relationship via explicit junction table.
Second, looks like you are using Entity Framework, in which case you'd better define and use navigation properties rather than manual joins.
Third, and the most important, the structure of the query is wrong. If you want to get a list of servers that may or may not belong to 1 or more groups, then you should start your query from Servers (the table which records you want to be always included, not from link table where some ServerID are missing) and then use left outer joins to the other tables like this:
var query =
from s in servers in context.Servers
join sg in context.ServerGroups on s.ID equals sg.ServerID
into s_sg from sg in s_sg.DefaultIfEmpty() // make the above LEFT OUTER JOIN
// You can remove the next two lines if all you need is the GroupId
// and keep them if you need some other Group field in the select
join g in context.Groups on sg.GroupID equals g.ID
into sg_g from g in sg_g.DefaultIfEmpty() // make the above LEFT OUTER JOIN
select new
{
ServerID = s.ID,
ServerIP = s.IP, // or sg.IP?
GroupID = (int?)sg.GroupID
};

MS Access Select Multiple Joins

I'm trying to select by c# and odbc from the following tables.
LinkTab (FromDevID, FromPort, ToDevID, ToPort)
DevList (ID,DevName...)
The result should look like
FromDevName | FromPort | ToDevName | ToDevPort
i tried already the following statement:
SELECT dev1.DevName, lt.FromPort, dev2.DevName, lt.ToPort
FROM (LinkTab lt
INNER JOIN DevList dev1 ON lt.FromDevID = dev1.ID)
INNER JOIN devList dev2 ON lt.ToDevID = dev2.ID
and I couldn't get all records. I guess there is a mistake at my join condition.
Presumably, you need left join:
SELECT dev1.DevName, lt.FromPort, dev2.DevName, lt.ToPort
FROM (LinkTab lt LEFT JOIN
DevList dev1
ON lt.FromDevID = dev1.ID
) LEFT JOIN
devList dev2
ON lt.ToDevID = dev2.ID;
The reason your query would not return all the rows is because the devises may not always match. If this is the case, then INNER JOIN will filter out the rows with unmatched devices. A LEFT JOIN will keep all the rows in the first table, assigning NULL for the columns from the second and third tables.

How to filter null value in sql

I have a situation in my sql statement. In this sql statement, I joined 3 tables together (Application_Detail, Teacher_Detail, and Class_Detail), and than I used WHERE to filter my table to find out how many teacher used this application, I found the following result.
As you can see in the 1st record, both teacher related and class related field are null. I am wondering is there a way to filter out the 1st record and only show the 2,3,4 record? because I want to only want to show the record if there are some value in teacherId, teacherName, class, or grade column.
teacherId teacherName applicationName class grade
1. NULL NULL Excel NULL NULL
2. 5 NULL Excel NULL NULL
3. NULL NULL Excel A 6
4 NULL NULL Excel B 2
Here is my SQL command
SELECT
td.teacherId,
teacherName,
applicationName,
class,
grade
FROM
[AppUser_Detail] as aud
LEFT OUTER JOIN [Teacher_Detail] as td ON aud.teacherId = td.teacherId
LEFT OUTER JOIN [Application_Detail] as ad ON aud.applicationId = ad.applicationId
LEFT OUTER JOIN [Class_Detail] as cd ON aud.classId = cd.classId
WHERE
aud.applicationId = 6 //I filter if my application Id is 6
Try this:
SELECT
td.teacherId,
teacherName,
applicationName,
class,
grade
FROM
[AppUser_Detail] as aud
LEFT OUTER JOIN [Teacher_Detail] as td ON aud.teacherId = td.teacherId
LEFT OUTER JOIN [Application_Detail] as ad ON aud.applicationId = ad.applicationId
LEFT OUTER JOIN [Class_Detail] as cd ON aud.classId = cd.classId
WHERE
td.teacherId is not null OR class is not null OR grade is not null
SELECT
td.teacherId,
teacherName,
applicationName,
class,
grade
FROM [AppUser_Detail] as aud
LEFT OUTER JOIN [Teacher_Detail] as td ON aud.teacherId = td.teacherId
LEFT OUTER JOIN [Application_Detail] as ad ON aud.applicationId = ad.applicationId
LEFT OUTER JOIN [Class_Detail] as cd ON aud.classId = cd.classId
WHERE
aud.applicationId = 6 //I filter if my application Id is 6
AND NOT (td.teacherId IS NULL AND class IS NULL AND grade IS NULL)
SELECT *
FROM (
SELECT td.teacherId AS [TeacherID]
,teacherName AS [TeacherName]
,applicationName AS [ApplicationName]
,class AS [Class]
,grade AS [Grade]
FROM [AppUser_Detail] AS aud
LEFT JOIN [Teacher_Detail] AS td ON aud.teacherId = td.teacherId
LEFT JOIN [Application_Detail] AS ad ON aud.applicationId = ad.applicationId
LEFT JOIN [Class_Detail] AS cd ON aud.classId = cd.classId
WHERE aud.applicationId = 6
)
WHERE TeacherID IS NOT NULL
OR TeacherName IS NOT NULL
OR Grade IS NOT NULL

How do I use multiple IDs from a table with an INNER JOIN using SQL?

I have a list of SiteUsers in one table and another table has columns with different types of owners (ID) for the record. For example, the SiteUserID in the SiteUsers table will be used for the SalesRepID, the StaffingManagerID, and RecruiterID in the Fill table. Of course, the SiteUserID is different for each of the values in the Fill table.
I'd like to return the name of the SiteUser for each ID column in the Fill Table.
How do I properly construct a JOIN statement to do this?
I'm guessing this is done through INNER JOIN, but I'm not sure.
My current select statement already has an INNER JOIN as I'm pulling the name of the FillType from another table. I'm using this in an asp.net application.
I'm not sure if this is even possible. Any help is appreciated.
Since each of the IDs in the Fills table allows null, you probably want to LEFT JOIN to the SiteUsers table like so:
SELECT f.FillID, s1.SiteUserLastName 'SalesRep', s2.SiteUserLastName 'StaffingManager', s3.SiteUserLastName 'Recruiter'
FROM Fills f
LEFT JOIN SiteUsers s1 on f.SalesRepID = s1.SiteUserID
LEFT JOIN SiteUsers s2 on f.StaffingManagerID = s2.SiteUserID
LEFT JOIN SiteUsers s3 on f.RecruiterID = s3.SiteUserID
You can always UNPIVOT the results like so:
SELECT
DISTINCT
unpvt.FillID
,unpvt.RepID
,unpvt.RepType
,s.SiteUserFirstName
,s.SiteUserLastName
FROM
(SELECT
FillID
,SalesRepID
,StaffingManagerID
,RecruiterID
FROM Fills
) f
UNPIVOT
(RepID FOR RepType IN
(SalesRepID, StaffingManagerID,RecruiterID)
) AS unpvt
JOIN SiteUsers AS s on unpvt.RepID = s.SiteUserID`
Obviously you can play with exact output (such as substituting the RepType for a different value with a CASE statement or whatnot.
My question is: why the piss-poor design? Instead of having three IDs in the Fills table, you should have a junction table between SiteUsers and Fills to allow many-to-many relationships. IF it were designed with a junction table, you'd never have had to ask this question.
You will have to join the Fill table with the SiteUsers table multiple times, one for each xxxID column in the Fills for which you want the SiteUser name and combine the results using an union as below:
select a.SiteUserId, a.SiteUserFirstName, a.SiteUserLastName
from dbo.SiteUsers a
inner join dbo.Fills b on b.SalesRepId = a.SiteUserId
UNION
select a.SiteUserId, a.SiteUserFirstName, a.SiteUserLastName
from dbo.SiteUsers a
inner join dbo.Fills b on b.StaffingManagerId = a.SiteUserId
UNION
select a.SiteUserId, a.SiteUserFirstName, a.SiteUserLastName
from dbo.SiteUsers a
inner join dbo.Fills b on b.RecruiterId = a.SiteUserId

Categories