I've been provided this old SQL code (table names changed) to replicate, and the JOIN syntax isn't something I've seen before, and is proving hard to google:
select <stuff>
from A
inner join B
on A.ID = B.A_ID
inner join C -- eh? No ON?
inner join D
ON C.C_ID = D.C_ID
ON B.C_ID = D.C_ID -- a second ON here? what?
When I saw the code, I assumed I'd be sent broken code and it wouldn't run.
But it does. (Sql Server 2012)
What does it do? Is there a more sensible / standard way of writing it? What's happening here?
While unusual, this is perfectly valid tsql. Typically you see this approach when you have an outer join to a set of related tables which are inner joined to one another. A better IMHO way to write this would be:
inner join B
on A.ID = B.A_ID
inner join (C inner join D ON C.C_ID = D.C_ID)
ON B.C_ID = D.C_ID
This makes the join logic clear - and it also helps the reader. Additionally, it lets the reader know that the developer did this intentionally. So let this be an example of poor coding. Comment things that are unusual. Explain things. Have someone review your code periodically to help improve your style and usage.
And you could write this in a "typical" style by rearranging the order of tables in the from clause - but I'll guess that the current version makes more logical sense with the real table names.
I ran it by a colleague who figured it out:
select <stuff>
from A
inner join B
on A.ID = B.A_ID
inner join ( C -- put a bracket here...
inner join D
ON C.C_ID = D.C_ID
) -- and one here
ON B.C_ID = D.C_ID
or to format it a little nicer:
select <stuff>
from A
inner join B
on A.ID = B.A_ID
inner join (
C
inner join D
ON C.C_ID = D.C_ID
)
ON B.C_ID = D.C_ID
I wasn't familiar with this kind of "sub-join" (I don't know what it's called), but this is much more readable and clear
Related
I am new in sql so i just dont know the difference between them. Does it affect compile time or something else? Can you explain it?
select a.name, b.salary from account a, bank b
where a.id = b.id;
or
select a.name, b.salary from account a
join bank b on a.id = b.id;
There is no difference. The latter is a newer (SQL-92) syntax and easier to read.
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.
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...
So I've been given a task where i should present the following:
ID, LNAME, FNAME, MNAME, BIRTH_DATE, RELG_CODE, NAT_CODE, PT_STATUS, RM_NO, DTTM_ADM
The tables are:
HISR_CODES, PASR_NAMES, PASR_PROFILE, PAST_PATIENT_ADM
--Viewing them using DESC--
So while I viewed them, I was told that the ID on these tables are the same. So what I did so far in the coding (I'll finish the rest but I need to make sure this works first):
SELECT
A.ID,
A.LNAME,
A.FNAME,
A.MNAME,
A.BIRTH_DATE,
C.RELG_CODE,
C.NAT_CODE,
B.PT_STATUS,
B.RM_NO,
B.DTTM_ADM
FROM
PASR_NAMES A,
PASR_PROFILE B,
PAST_PATIENT_ADM C,
HISR_CODES D
WHERE
A.ID = B.ID
AND
B.ID = C.ID
AND
C.ID = D.ID
Is there a way to tell that all of the ID's from the tables are the same? A simpler code than going on like this:
WHERE
A.ID = B.ID
AND
B.ID = C.ID
AND
C.ID = D.ID
Or is JOIN - ON the only option for this?
You can use NATURAL JOIN as below:
SELECT
A.ID,
A.LNAME,
A.FNAME,
A.MNAME,
A.BIRTH_DATE,
C.RELG_CODE,
C.NAT_CODE,
B.PT_STATUS,
B.RM_NO,
B.DTTM_ADM
FROM
PASR_NAMES A
NATURAL JOIN PASR_PROFILE B
NATURAL JOIN PAST_PATIENT_ADM C
NATURAL JOIN HISR_CODES D;
From Oracle Reference, "A natural join is based on all columns in the two tables that have the same name." So, there is a chance that the joins happen based on other columns as well. Therefore, it is recommended that you still use the INNER JOIN syntax and explicitly specify the JOIN columns.
References:
NATURAL JOIN on Oracle® Database SQL Language Reference
Related SO question
Use the proper join syntax:
FROM PASR_NAMES A JOIN
PASR_PROFILE B
ON A.ID = B.ID JOIN
PAST_PATIENT_ADM C
ON B.ID = C.ID JOIn
HISR_CODES D
ON C.ID = D.ID
Or:
FROM PASR_NAMES A JOIN
PASR_PROFILE B
USING (ID) JOIN
PAST_PATIENT_ADM C
USING (ID)
HISR_CODES D
USING (ID)
I would discourage you from using the natural join. It might seem like the right thing at first. However, the semantics of the query are highly dependent on the structure of the tables. If columns are renamed, removed, or added, the query might still work but produce highly unexpected results.
I need to join multiple tables in access.
Access has some odd syntax when it comes to joins, and I cant seem to get this right
In particular, C needs to consider fields from both A and B
select a.*, B.*, c.*
from
(tblOne as A
Left join tblTwo as B on A.ParentId = B.Id )
left join tblThree as C on C.ParentId = B.Id and C.ShoeSize = A.ShoeSize
I have encountered and gotten past putting each Parens thing when more than 2 tables are involved.
I can join in C as long as I only want to refer to 1 of the other tables.
This type thing is fairly straight forward in SQL Server.
Any help would be appreciated, I cant seem to find an answer on google.
The client is currently using ms Access 2003. If the problem can be remedied by a newer version, I am pretty I could talk them into an upgrade.
thanks
greg
I just tried the following in Access 2010 and it seems to work, although I must admit that I don't have a clear picture in my mind as to how this might be used in the "real world"...
SELECT ab.*, c.*
FROM
(
SELECT a.ID AS ID1, a.ShoeSize AS ShoeSize1, b.ID AS ID2
FROM tblOne a LEFT JOIN tblTwo b
ON a.ParentId = b.Id
) ab LEFT JOIN tblThree c
ON c.ParentId = ab.ID2 and c.ShoeSize = ab.ShoeSize1