How to filter the left join in sql - sql

This is the code:
SELECT c.ChapterNo, c.Title, l.LessonNo, l.Title
FROM Chapter c
LEFT JOIN Lesson l ON c.ChapterNo = l.ChapterNo
but i want to filter the Chapter Table by Chapter's Description A. I already used this:
SELECT c.ChapterNo, c.Title, l.LessonNo, l.Title
FROM Chapter c
LEFT JOIN Lesson l ON c.ChapterNo = l.ChapterNo
WHERE c.Desc = 'geometry'
and this
SELECT c.ChapterNo, c.Title, l.LessonNo, l.Title
FROM Chapter c
LEFT JOIN Lesson l ON c.ChapterNo = l.ChapterNo AND c.Desc = 'geometry'
but it does not work. I dont know why...

It does not work because you need to put the condition in the where clause:
SELECT c.ChapterNo, c.Title, l.LessonNo, l.Title
FROM Chapter c LEFT JOIN
Lesson l
ON c.ChapterNo = l.ChapterNo
WHERE c.Desc = 'geometry';
The rules for a left join are simple: Keep all the rows in the first table regardless of whether or not the WHERE clause evaluates to true. So, a filter on the first table does not reduce the number of rows.

Related

Adding From statement to Join statements

So the code has multiple join statements, and all I need to add is a where clause that checks one value. The table I need to reference is not used in the From statement which includes multiple joins. Is there anyway to add a regular FROM statement without disrupting the JOINS
SELECT D.data
H.otherData
FROM
Dada AS D
JOIN Haha AS H
ON D.ID = H.ID
WHERE
C.Value = x --This is what I want to do. Can I add another from statement that doesn't affect the join statement
Not possible without including C somewhere.
What you're saying is equivalent to "List all the Countries where the Person is called Tom"
You can add C table, but it has to be with a JOIN. Maybe you want a CROSS JOIN, which is the cartesian product of the joining tables against this new table C and doesn't require any condition (you can filter the results with a WHERE condition).
SELECT D.data
H.otherData
FROM
Dada AS D
JOIN Haha AS H
ON D.ID = H.ID
CROSS JOIN C
WHERE
C.Value = x
In this particular, case it would be the same as:
SELECT D.data
H.otherData
FROM
Dada AS D
JOIN Haha AS H
ON D.ID = H.ID
JOIN C
ON C.Value = x
If you want to filter the first JOIN depending on a value from C then you need to put the condition on a subquery on the WHERE, like an IN or EXISTS. There has to be some correlation (a column or expression that both share) between your first JOIN and this table C, otherwise there is no point in filtering.
For example:
SELECT D.data
H.otherData
FROM
Dada AS D
JOIN Haha AS H
ON D.ID = H.ID
WHERE EXISTS (SELECT 'value exists on table C' FROM C WHERE C.Value = D.data)

SQL SELECT QUERY RELATION TABLES

I'm a little lost with sql. I'm trying to get values of referenced tables, and i have to go throught 6 tables but i'm not getting any result. This is my code:
SELECT v.VEHICLEPLATE, p.NAME
FROM ITV i, VEHICLE v, BUYS b, PERSON p, CENTER c, WORKER w
WHERE
w.NICK = 'PEPE' AND
c.ID = w.CENTERID AND
v.VEHICLEPLATE = i.VEHICLEPLATE AND
v.VEHICLEPLATE = b.VEHICLEPLATE AND
p.ID = b.PERSON;
I want to get all the records in ITV where PEPE works.
Someone can help or orient me please?
Thank you.
Use explicit joins for your tables instead of implicit, like this:
SELECT v.VEHICLEPLATE, p.NAME
FROM ITV i
INNER JOIN VEHICLE v ON v.VEHICLEPLATE = i.VEHICLEPLATE
INNER JOIN BUYS b ON v.VEHICLEPLATE = b.VEHICLEPLATE
INNER JOIN PERSON p ON p.ID = b.PERSON
INNER JOIN CENTER c --Need join condition here
INNER JOIN WORKER w ON c.ID = w.CENTERID
WHERE w.NICK = 'PEPE';
It's a lot easier to read, and the implicit style you have in your question is depreciated.
Now you can see you are missing your join condition for INNER JOIN CENTER C. You may have further issues but start here and if it still isn't right, provide us with your current results and your expected results.

How to join three tables in sql server

I have three tables:
Chapter (ChapterNo, Desc)
Lesson (LessonNO, Dec, ChapterNo)
Case (CaseNo, Desc, LessonNo)
As you see, the three tables are all connected. What I want is to return all the chapters (even without lessons in it), all the lessons (even without cases in it) and all the cases.
I am sorry to say but I really don't have an idea so I have no sample code. I hope my explanations are enough.
USE LEFT JOIN:
SELECT
C.*,
L.*,
CA.*
FROM Chapter C
LEFT JOIN Lesson L ON C.ChapterNo=L.ChapterNo
LEFT JOIN Case CA ON L.LessonNo=CA.LessonNo
Use Left Join query in order to get your desired result
As for naming of tables. Don't use Case as table name because it is a reserved word for SQL.
SELECT CH.ChapterNo,CH.Desc,LE.LessonNo,LE.Dec,CA.CaseNo,CA.Desc FROM Chapter CH
LEFT JOIN Lesson LE ON CH.ChapterNo = LE.ChapterNo LEFT JOIN Cases CA ON LE.LessonNo = CA.LessonNO
SELECT *
FROM Chapter C
LEFT JOIN Lesson L ON C.ChapterNo=L.ChapterNo
LEFT JOIN Case CA ON L.LessonNo=CA.LessonNo
Select * From Chapter c
Left Join Lesson l On c.ChapterNo=l.ChapterNo
Left Join Case cs On cs.LessonNo=l. LessonNo

SQL - Consecutive "ON" Statements

As I was cleaning up some issues in an old view in our database I came across this "strange" join condition:
from
tblEmails [e]
join tblPersonEmails [pe]
on (e.EmailID = pe.EmailID)
right outer join tblUserAccounts [ua]
join People [p]
on (ua.PersonID = p.Id)
join tblChainEmployees [ce]
on (ua.PersonID = ce.PersonID)
on (pe.PersonID = p.Id)
Table tblUserAccounts is referenced as a right outer join, but the on condition for it is not declared until after tblChainEmployees is referenced; then there are two consecutive on statements in a row.
I couldn't find a relevant answer anywhere on the Internet, because I didn't know what this kind of join is called.
So the questions:
Does this kind of "deferred conditional" join have a name?
How can this be rewritten to produce the same result set where the on statements are not consecutive?
Maybe this is a "clever" solution when there has always been a simpler/clearer way?
(1) This is just syntax and I've never heard of some special name. If you read carefully this MSDN article you'll see that (LEFT|RIGHT) JOIN has to be paired with ON statement. If it's not, expression inside is parsed as <table_source>. You can put parentheses to make it more readable:
from
tblEmails [e]
join tblPersonEmails [pe]
on (e.EmailID = pe.EmailID)
right outer join
(
tblUserAccounts [ua]
join People [p]
on (ua.PersonID = p.Id)
join tblChainEmployees [ce]
on (ua.PersonID = ce.PersonID)
) on (pe.PersonID = p.Id)
(2) I would prefer LEFT syntax, with explicit parentheses (I know, it's a matter of taste). This produces the same execution plan:
FROM tblUserAccounts ua
JOIN People p ON ua.PersonID = p.Id
JOIN tblChainEmployees ce ON ua.PersonID = ce.PersonID
LEFT JOIN
(
tblEmails e
JOIN tblPersonEmails pe ON e.EmailID = pe.EmailID
) ON pe.PersonID = p.Id
(3) Yes, it's clever, just like some C++ expressions (i.e. (i++)*(*t)[0]<<p->a) on interviews. Language is flexible. Expressions and queries can be tricky, but some 'arrangements' lead to readability degradation and errors.
Looks to me like you have tblEmail and tblPerson with their own independent IDs, emailID and ID (person), a linking table tblPersonEmail with the valid pairs of emailID/IDs, and then the person table may have a 1-1 relationship with UserAccount, which may then have a 1-1 relationship with chainEmployee, so to get rid of the RIGHT OUTER JOIN in favor of LEFT, I'd use:
FROM
((tblPerson AS p INNER JOIN
(tblEmail AS e INNER JOIN
tblPersonEmail AS pe ON
e.emailID = pe.emailID) ON
p.ID = pe.personID) LEFT JOIN
tblUserAccount AS ua ON
p.ID = ua.personID) LEFT JOIN
tblChainEmployee AS ce ON
ua.personID = ce.personID
I can't think of a great practical example of this off the top of my head so I'll give you a generic example that hopefully makes sense. Unfortunately I'm not aware of a generic name for this either.
Many people will start off with a query like this:
select ...
from
A a left outer join
B b on b.id = a.id left outer join
C c on c.id2 = b.id2;
The look at the results and realize that they really need to eliminate the rows in B that don't have a corresponding C but if you tried to say where b.id2 is not null and c.id2 is not null you've defeated the whole purpose of the left join from A.
So next you try to do this but it doesn't take long to figure out it's not going to work. The inner join at the tail end of the chain has basically converted both the joins to inner joins.
select ...
from
A a left outer join
B b on b.id = a.id inner join
C c on c.id2 = b.id2;
The problem seems simple yet it doesn't work right. Essentially after you ponder for a while you discover that you need to control the join order and do the inner join first. So the three queries below are equivalent ways to accomplish that. The first one is probably the one you're more familiar with:
select ...
from
A a left outer join
(select * from B b inner join C c on c.id2 = b.id2) bc
on bc.id = a.id
select ...
from
A a left outer join
B b inner join
C c on c.id2 = b.id2
on b.id = a.id
select ...
from
B b inner join
C c on c.id2 = b.id2 right outer join -- now they can be done in order
A a on a.id = b.id
You query is a little more complicated but ultimately the same issues came into play which is where the odd stuff came from. SQL has evolved and you have to remember that platforms didn't always have the fancy things like derived tables, scalar subqueries, CTEs so sometimes people had to write things this way. And then there were graphical query builders with a lot of limitations in older versions of tools like Crystal Report that didn't allow for complex join conditions...

SQL joining three tables, join precedence

I have three tables: R, S and P.
Table R Joins with S through a foreign key; there should be at least one record in S, so I can JOIN:
SELECT
*
FROM
R
JOIN S ON (S.id = R.fks)
If there's no record in S then I get no rows, that's fine.
Then table S joins with P, where records is P may or may not be present and joined with S.
So I do
SELECT
*
FROM
R
JOIN S ON (S.id = R.fks)
LEFT JOIN P ON (P.id = S.fkp)
What if I wanted the second JOIN to be tied to S not to R, like if I could use parentheses:
SELECT
*
FROM
R
JOIN (S ON (S.id = R.fks) JOIN P ON (P.id = S.fkp))
Or is that already a natural behaviour of the cartesian product between R, S and P?
All kinds of outer and normal joins are in the same precedence class and operators take effect left-to-right at a given nesting level of the query. You can put the join expression on the right side in parentheses to cause it to take effect first. Remember that you will have to move the ON clauses around so that they stay with their joins—the join in parentheses takes its ON clause with it into the parentheses, so it now comes textually before the other ON clause which will be after the parentheses in the outer join statement.
(PostgreSQL example)
In
SELECT * FROM a LEFT JOIN b ON (a.id = b.id) JOIN c ON (b.ref = c.id);
the a-b join takes effect first, but we can force the b-c join to take effect first by putting it in parentheses, which looks like:
SELECT * FROM a LEFT JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);
Often you can express the same thing without extra parentheses by moving the joins around and changing the direction of the outer joins, e.g.
SELECT * FROM b JOIN c ON (b.ref = c.id) RIGHT JOIN a ON (a.id = b.id);
When you join the third table, your first query
SELECT
*
FROM
R
JOIN S ON (S.id = R.fks)
is like a derived table to which you're joining the third table. So if R JOIN S produces no rows, then joining P will never yield any rows (because you're trying to join to an empty table).
So, if you're looking for precedence rules then in this case it's just set by using LEFT JOIN as opposed to JOIN.
However, I may be misunderstanding your question, because if I were writing the query, I would swap S and R around. eg.
SELECT
*
FROM
S
JOIN R ON (S.id = R.fks)
The second join is tied to S as you explicity state JOIN P ON (P.id = S.fkp) - no column from R is referenced in the join.
with a as (select 1 as test union select 2)
select * from a left join
a as b on a.test=b.test and b.test=1 inner join
a as c on b.test=c.test
go
with a as (select 1 as test union select 2)
select * from a inner join
a as b on a.test=b.test right join
a as c on b.test=c.test and b.test=1
Ideally, we would hope that the above two queries are the same. However, they are not - so anybody that says a right join can be replaced with a left join in all cases is wrong. Only by using the right join can we get the required result.