SQL - inner join before left join - sql

I have come across some sql that has an inner join right before a left join.
From Table t
INNER JOIN vw_User i ON t.UserID = i.UserID
LEFT JOIN UserTypeTwo it ON t.UserTypeTwoID = it.UserTypeTwoID
Can someone please help me visualize how this works. I can visualize the two joins separately, but since they are one after the other, how do they work together?

See the following image, don't have enough rep to embed it.
http://i.imgur.com/pdMaz56.png

IMO, no better way to express joins than like this:

What will happens is that you are just appending more columns to Table T.
Basically what happens is that Table T has no relationship to UserTypeTwo, but it does to vw_user. Then you need some data from UserTypeTwo but since Table T can't join to userTypeTwo you need a table to connect them both, which is where vw_user comes in which should have a relation to UserTypeTwo.
Basically this query is being used because you need columns from Table T and UserTypeTwo(and probably vw_User as well) so you need to join all three of them.
Table T has FK for vw_User
vw_User has FK to UserTypeTwo
UserTypeTwo has column that you need
(it doesnt necessarily need to be a foreign key but I'm assuming you know this since you have join knowledge).
I hope I was able to clarify what is happening.

Related

How to join two tables first then join to another table

I have a DB2 database and I have to join three tables. I would like to join first two tables and after joining firs two tables, I would like to join the joined table to another third table. I tried using left join but couldn't find a result as I expected. I tried the following:
select AFJKAR as "ELR_Elig_Redirect_SchdID",
AFEZAM as "Priority",
AFTSAS as "ELC_Status",
AFT7CE as "ELC_From_Date",
AFT8CE as "ELC_Thru_Date",
AFTTAS as "ELC_Redirect_Action",
AFJLAR as "GPI_List",
AIZAHA as "GPI_List_ID",
AILUIG as "GPI_Number",
AICXHG as "GPI_From_Date",
AICYHG as "GPI_Thru_Date",
SUEFC4 as "GPI_ID",
SUB4T3 as "Drug_Name"
from CLMPRDFIL.RCELCP as RCE
left join CLMPRDFIL.RCGP2P as RCG on RCE.AFJLAR = RCG.AIZAHA
left join CLMPRDFIL.RCGPIP as RCGP on RCG.AIZAHA = RCGP.SUEFC4;
Basically, I would like to join RCE and RCGP2P tables first. After joining this, I would like to join it by RCGPIP.
Use a corresponding optimization profile / guideline for this.
Optimization profiles and guidelines.
You may specify the desired join order there, if you believe, that you may achieve better performance with particular join order.
Note, that you should try to collect statistics on these tables first to make the Db2 optimizer use correct join order. For example, try to create a statistical view on first 2 tables using their join keys and collect statistics on it. Look at the access plan of your original query afterwards to check, if you get desired join order.

Access SQL subquery access field from parent

I have a SQL query that works in Access 2016:
SELECT
Count(*) AS total_tests,
Sum(IIf(score>=securing_threshold And score<mastering_threshold,1,0)) AS total_securing,
Sum(IIf(score>=mastering_threshold,1,0)) AS total_mastering,
total_securing/Count(*) AS percent_securing,
total_mastering/Count(*) AS percent_mastering,
(Count(*)-total_securing-total_mastering)/Count(*) AS percent_below,
subjects.subject,
students.year_entered,
IIf(Month(Date())<9,Year(Date())-students.year_entered+6,Year(Date())-students.year_entered+7) AS current_form,
groups.group
FROM
((subjects
INNER JOIN tests ON subjects.ID = tests.subject)
INNER JOIN (students
INNER JOIN test_results ON students.ID = test_results.student) ON tests.ID = test_results.test)
LEFT JOIN
(SELECT * FROM group_membership LEFT JOIN groups ON group_membership.group = groups.ID) As g
ON students.ID = g.student
GROUP BY subjects.subject, students.year_entered, groups.group;
However, I wish to filter out irrelevant groups before joining them to my table. The table groups has a column subject which is a foreign key.
When I try changing ON students.ID = g.student to ON students.ID = g.student And subjects.ID = g.subject I get the error 'JOIN expression not supported'.
Alternatively, when I try adding WHERE subjects.ID = groups.subject to the subquery, it asks me for the parameter value of subjects.ID, although it is a column in the parent query.
Googling reveals many similar errors but they were all resolved by changing the brackets. That didn't help.
Just in case the table relationships help:
Thank you.
EDIT: Sample database at https://www.dropbox.com/s/yh80oooem6gsni7/student%20tracker.ACCDB?dl=0
MS Access queries with many joins are difficult to update by SQL alone as parenetheses pairings are required unlike other RDBMS's and these pairings must follow an order. Moreover, some pairings can even be nested. Hence, for beginners it is advised to build queries with complex and many joins using the query design GUI in the MS Office application and let it build out the SQL.
For a simple filter on the g derived table, you could filter subject on the derived table, g, but likely you want want all subjects:
...
(SELECT * FROM group_membership
LEFT JOIN groups ON group_membership.group = groups.ID
WHERE groups.subject='Earth Science') As g
...
So for all subjects, consider re-building query from scratch in GUI that nearly mirrors your table relationships which actually auto-links joins in the GUI. Then, drop unneeded tables.
Usually you want to begin with the join table or set like groups and group_membership or tests and test_results. In fact, consider saving the g derived table as its own query.
Then add the distinct record primary source tables like students and subjects.
You may even need to play around with order in FROM and JOIN clauses to attain desired results, and maybe even add the same table in query. And be careful with adding join tables like group_membership (two one-to-many links), to GROUP BY queries as it leads to the duplicate record aggregation. So you may need to join aggregates queries by subject.
Unless you can post content of all tables, from our perspective it is difficult to help from here.
Your subquery g uses a LEFT JOIN, but there is a enforced 1:n relation between the two tables, so there will always be a matching group. Use a INNER JOIN instead.
With g.subject you are trying to join on a column that is on the right side of a left join, that cannot really work.
Also you shouldn't use SELECT * on a join of tables with identical column names. Include only the qualified column names that you need.
LEFT JOIN
(SELECT group_membership.student, groups.group, groups.subject
FROM group_membership INNER JOIN groups
ON group_membership.group = groups.ID) As g
ON (students.ID = g.student AND subjects.ID = g.subject)
I would call the columns in group_membership group_ID and student_ID to avoid confusion.
I don't have the database to test, but I would use subject table as subquery:
(SELECT * FROM subject WHERE filter out what you don't need) Subj
Then INNER JOIN this new Subj Table in your query which would exclude irrelevant groups.
Also I would never create join in WHERE clause (WHERE subjects.ID = groups.subject), what this does it creates cartesian product (table with all the possible combinations of subjects.ID and groups.subject) then it filters out records to satisfy your join. When dealing with huge data it might take forever or crash.
Error related to "Join expression may not be supported"; do datatypes match in those fields?
I solved it by (a lot of trial and error and) taking the advice here to make queries in the GUI and joining them. The end result is 4 queries deep! If the database was bigger, performance would be awful... but now its working I can tweak it eventually.
Thank you everybody!

Is it possible to detect where the join fails on a certain record?

Please bear with me as this may be a question without a possible answer, but I hope I describe it correctly..
I have a query which joins a number of tables and produces results, and here is the SQL:
SELECT
dbo.Property.PropertyPK,
dbo.Tenancy.TenancyPK,
dbo.Tenant.ContactFK,
dbo.Contacts.strTitle,
dbo.Contacts.strFirstName,
dbo.Contacts.strSurname
FROM dbo.Property
INNER JOIN dbo.Tenancy ON dbo.Property.PropertyPK = dbo.Tenancy.PropertyFK
INNER JOIN dbo.Tenant ON dbo.Tenancy.TenancyPK = dbo.Tenant.TenancyFK
INNER JOIN dbo.Contacts ON dbo.Tenant.ContactFK = dbo.Contacts.ContactPK
The main table is the Property table and I filter out one row by specifying a PropertyPK in my criteria..
My question is.. If the Tenant or Contact record does not exist and I run my query in SQL Management Studio of course I get a message saying there are no rows but can I determine at what stage the join has failed between two tables?
I can of course check this in management studio but I am trying to help the user on the application side to inform them of why there are no rows. My application is in VB and I will write that check if there are no rows and I cannot determine it in SQL..
Sorry for the question in advance..
Derek.. :)
Simply use a LEFT JOIN:
SELECT p.PropertyPK, ty.TenancyPK, t.ContactFK,
c.strTitle, c.strFirstName, c.strSurname
FROM dbo.Property p LEFT JOIN
dbo.Tenancy ty
ON p.PropertyPK = ty.PropertyFK LEFT JOIN
dbo.Tenant t
ON ty.TenancyPK = t.TenancyFK LEFT JOIN
dbo.Contacts c
ON t.ContactFK = c.ContactPK;
This will keep all rows in the Property table. You can then see which primary keys are NULL to see if there were matches in the other tables.
Note that the query is much easier to write and to read when you use table aliases.

When to use SQL natural join instead of join .. on?

I'm studying SQL for a database exam and the way I've seen SQL is they way it looks on this page:
http://en.wikipedia.org/wiki/Star_schema
IE join written the way Join <table name> On <table attribute> and then the join condition for the selection. My course book and my exercises given to me from the academic institution however, use only natural join in their examples. So when is it right to use natural join? Should natural join be used if the query can also be written using JOIN .. ON ?
Thanks for any answer or comment
A natural join will find columns with the same name in both tables and add one column in the result for each pair found. The inner join lets you specify the comparison you want to make using any column.
IMO, the JOIN ON syntax is much more readable and maintainable than the natural join syntax. Natural joins is a leftover of some old standards, and I try to avoid it like the plague.
A natural join will find columns with the same name in both tables and add one column in the result for each pair found. The inner join lets you specify the comparison you want to make using any column.
The JOIN keyword is used in an SQL statement to query data from two or more tables, based on a relationship between certain columns in these tables.
Different Joins
* JOIN: Return rows when there is at least one match in both tables
* LEFT JOIN: Return all rows from the left table, even if there are no matches in the right table
* RIGHT JOIN: Return all rows from the right table, even if there are no matches in the left table
* FULL JOIN: Return rows when there is a match in one of the tables
INNER JOIN
http://www.w3schools.com/sql/sql_join_inner.asp
FULL JOIN
http://www.w3schools.com/sql/sql_join_full.asp
A natural join is said to be an abomination because it does not allow qualifying key columns, which makes it confusing. Because you never know which "common" columns are being used to join two tables simply by looking at the sql statement.
A NATURAL JOIN matches on any shared column names between the tables, whereas an INNER JOIN only matches on the given ON condition.
The joins often interchangeable and usually produce the same results. However, there are some important considerations to make:
If a NATURAL JOIN finds no matching columns, it returns the cross
product. This could produce disastrous results if the schema is
modified. On the other hand, an INNER JOIN will return a 'column does
not exist' error. This is much more fault tolerant.
An INNER JOIN self-documents with its ON clause, resulting in a
clearer query that describes the table schema to the reader.
An INNER JOIN results in a maintainable and reusable query in
which the column names can be swapped in and out with changes in the
use case or table schema.
The programmer can notice column name mis-matches (e.g. item_ID vs itemID) sooner if they are forced to define the ON predicate.
Otherwise, a NATURAL JOIN is still a good choice for a quick, ad-hoc query.

Possible to combine two tables without losing all data by using JOINS

I have a table as below and I would like to know if I can still join them together, without losing existing data from both tables when they are combined by referencing JOIN methods.
Table details - VIEW Table
SELECT
r.domainid,
r.DomainStart,
r.Domain_End,
r.ddid,
r.confid,
r.pdbcode,
r.chainid,
d.pdbcode AS "CATH_PDBCODE",
d.cathbegin AS "CATH_BEGIN",
d.cathend AS "CATH_END"
FROM dyndom_domain_table r
JOIN cath_domains d ON d.pdbcode::character(4) = r.pdbcode
ORDER BY confid ASC;
As you can see, dyndom_domain_table is a VIEW Table that I have created to make it easier for me to use JOIN clauses with the other table that has the same pdbcode.
So far it just returns all of the data that matches with the PDB Code. What I would like to do is return all of the data that both matches and doesn't match each other's PDB Code.
Is there a rule in which I can apply it to? Or is it not possible?
I believe you want a FULL OUTER JOIN rather than just a JOIN (which is, by default, an INNER JOIN). In a FULL OUTER JOIN, every row in each table will correspond to some row in the result table; rows from one table that don't match the other will be extended with NULLs to fill the missing column.
So FULL OUTER JOIN instead of just JOIN, and that should do you.
I think you're asking for a left join, but I'm not sure.
SELECT
r.domainid,
r.DomainStart,
r.Domain_End,
r.ddid,
r.confid,
r.pdbcode,
r.chainid,
d.pdbcode AS "CATH_PDBCODE",
d.cathbegin AS "CATH_BEGIN",
d.cathend AS "CATH_END"
FROM dyndom_domain_table r
LEFT JOIN cath_domains d ON d.pdbcode::character(4) = r.pdbcode
ORDER BY confid ASC;