SQL - join multiple tables, with one little catch - sql

My apologies in advance if this particular question has already been asked and answered ... there so many different particular ways the JOIN command is used that it can be difficult to find the exact answer to a given problem. I'm a SQL novice, so ... if the solution exists, feel free to point me to it.
I'm trying to join 3 different tables, and I believe what I want is equivalent to a FULL OUTER JOIN (not supported by MySQL, as I understand) on all 3 tables. Consider a Venn diagram with 3 circles; I want the full union of all 3 circles, including the full intersection, all three pair-wise joins (where one table returns NULLs), and all three single instances (where two tables return NULLs). I believe what I've got here will work, but it's brute-force and I'm sure there is a more efficient way. I'm also a bit concerned with my use of WHERE NOT EXISTS, so please correct me if necessary. Here's the gist of my code:
// Intersection of all three tables
SELECT [table1.cols], [table2.cols], [table3.cols]
FROM table1
INNER JOIN table2
ON table1.col1 = table2.col1
INNER JOIN table3
ON table1.col1 = table3.col1
UNION ALL
// Intersection of tables one and two
SELECT [table1.cols], [table2.cols], [NULLS]
FROM table1
INNER JOIN table2
ON table1.col1 = table2.col1
WHERE NOT EXISTS (table1.col1 = table3.col1)
UNION ALL
// Intersection of tables two and three
SELECT [NULLS], [table2.cols], [table3.cols]
FROM table2
INNER JOIN table3
ON table2.col1 = table3.col1
WHERE NOT EXISTS (table2.col1 = table1.col1)
UNION ALL
// Intersection of tables three and one
SELECT [table1.cols], [NULLS], [table3.cols]
FROM table3
INNER JOIN table1
ON table3.col1 = table1.col1
WHERE NOT EXISTS (table3.col1 = table2.col1)
UNION ALL
// Only in table one
SELECT [table1.cols], [NULLS], [NULLS]
FROM table1
WHERE NOT EXISTS ((table1.col1 = table2.col1))
AND NOT EXISTS ((table1.col1 = table3.col1))
UNION ALL
// Only in table two
SELECT [NULLS], [table2.cols], [NULLS]
FROM table2
WHERE NOT EXISTS ((table2.col1 = table1.col1))
AND NOT EXISTS ((table2.col1 = table3.col1))
UNION ALL
// Only in table three
SELECT [NULLS], [NULLS], [table3.cols]
FROM table3
WHERE (NOT EXISTS (table3.col1 = table1.col1))
AND (NOT EXISTS (table3.col1 = table2.col1))
TIA for your help, and your grace. :)

to simulate your full outer join, I would pre-query just the UNIQUE IDs you are EXPECTING, then LEFT JOIN to each other...
select
AllPossibleKeys.CommonID,
T1a.*,
T2a.*,
T3a.*
from
( select distinct T1.col1 as CommonID
from table1 T1
UNION
select distinct T2.col1 as CommonID
from table2 T2
UNION
select distinct T3.col1 as CommonID
from table1 T3 ) as AllPossibleKeys
LEFT JOIN table1 T1a
on AllPossibleKeys.CommonID = T1a.col1
LEFT JOIN table2 T2a
on AllPossibleKeys.CommonID = T2a.col1
LEFT JOIN table3 T3a
on AllPossibleKeys.CommonID = T3a.col1

Related

Conditional Join if Exists

I need to join two tables together based on a three-column key stack. The problem is sometimes one of the key columns is translated and mapped differently in another table. I will attempt to example my issue using code:
select t1.TQ
from table1 t1
left join table2 t2 on t1.comp_cd = t2.comp_cd and t1.plcy_frm = t2.plcy_frm
and t1.val_cd = t2.val_cd
The columns "comp_cd" and "plcy_frm" are fine, however the problem is with val_cd. Sometimes the val_cd in table2 does not map correctly to table1 and must go through a third table, table3. Table3 structure is below:
Val_Cd Mapped_Val_Cd
A123 A564
So -> I need to join on Mapped_Val_Cd value when it exists in Table3, but join on Val_Cd from Table2 when Val_Cd does not exist in Table3.
I hope this makes sense - I have tried Case when exists syntax but cannot get that to work.
Assuming there are no duplicates in table3, you can left join it in and then choose the value that you want in the on clause:
select t1.TQ
from table1 t1 left join
table3 t3
on t1.val_cd = t3.val_cd
table2 t2
on t1.comp_cd = t2.comp_cd and
t1.plcy_frm = t2.plcy_frm and
t1.val_cd = coalesce(t3.Mapped_Val_Cd, t2.val_cd);

SQL join to return a table with multiple columns from other tables replacing its own

I am trying to write an SQL query that will return Table1, which has 10 columns. This table consists of a primary key id, 4 foreign key Id columns, and 5 other columns that I want to return but not change. The goal is to do a join to replace the foreign key Ids with their descriptions that are held in other tables.
Here is one attempt with the first FK Id:
Select * from Table1 t1
left join Table2 t2
on t1.BranchId = t2.BranchId;
This left join returns the description from table2, but does not replace it.
Here is another with the first FK Id:
Select t2.BranchName from Table1 t1
left join Table2 t2
on t1.BranchId = t2.BranchId;
This returns the name I want, but does not return table1 fully.
For the sake of an example you could pretend that OtherName3, OtherName4, OtherName5 are in tables Table3, Table4, Table5, respectively.
This may seem trivial for experienced SQL devs, but I am having a hard time figuring out the syntax.
Thanks!
I'm not sure what you mean by replace it.
I think you just need to list out all the columns you want:
Select t1.col1, t1.col2, t1.col3, . . .,
t2.name
from Table1 t1 left join
Table2 t2
on t1.BranchId = t2.BranchId;
I don't know what you mean by 'replace' but you just need to qualify what columns from which table you want. That goes for all tables you are joined to, especially if they have the same column name in multiple tables. I put junk columns in since I don't know your tables but you should get the general idea.
Select t2.BranchName, t1.BranchId, t1.Name, t1.Amount, t2.BranchLocation from Table1 t1
left join Table2 t2
on t1.BranchId = t2.BranchId;
I think this is what you are looking for:
select t1.*, t2.BranchName from Table1 t1
left join Table2 t2
on t1.BranchId = t2.BranchId;
Return Table1 fully (all columns) and only the description (BranchName) from Table2.
If using SQL Server, see all syntax options for the SELECT clause here:
https://msdn.microsoft.com/en-us/library/ms176104.aspx

How to select records that do not exist in two (or more) tables

I have 3 tables of accounts that all contain the same fields. Table1 contains all accounts while Table2 and Table3 contain subsets of the accounts. I'm trying to select records in Table1 that do no exist in Table2 or Table3.
Let's say the table layout is like this and is the same for all 3 tables:
|AcctNum|Name|State|
I know how to do this if it was just Table1 and Table2, using a left join and Is Null, but the 3rd table is throwing me. Is this possible to do in one query? Can you combine left joins? I should point out I'm using Access 2010.
Yes you can combine left joins and with the odd syntax Access uses the query should look like this:
SELECT T1.AcctNum
FROM (Table1 AS T1 LEFT JOIN Table2 AS T2 ON T1.AcctNum = T2.AcctNum)
LEFT JOIN Table3 AS T3 ON T1.AcctNum = T3.AcctNum
WHERE (((T2.AcctNum) Is Null) AND ((T3.AcctNum) Is Null));
You can use Access to create a view called TableCombined that is a union of both Table2 and Table3.
At that point, you can use your left join and Is Null query and join TableCombined to Table1.
Hope this helps!
You can also do a NOT EXISTS statement which makes sense logically for what you are trying to achieve.
For example:
SELECT ACCTNUM
FROM TABLE1
WHERE NOT EXISTS (SELECT TABLE2.ACCTNUM FROM TABLE2 INNER JOIN TABLE3 WHERE TABLE2.ACCTNUM IS NULL AND TABLE3.ACCTNUM IS NULL)

Is it possible to use subquery in join condition in Access?

In postgresql I can use subquery in join condition
SELECT *
FROM table1 LEFT JOIN table2
ON table1.id1 = (SELECT id2 FROM table2 LIMIT 1);
But when I try to use it in Access
SELECT *
FROM table1 LEFT JOIN table2
ON table1.id1 = (SELECT TOP 1 id2 FROM table2);
I get syntax error. Is it actually impossible in Access or just my mistake?
I know that I can get the same result with WHERE, but my question is about possibilities of JOIN in Access.
It's not possible, per the MSDN documentation:
Syntax
FROM table1 [ LEFT | RIGHT ] JOIN table2 ON table1.field1 compopr table2.field2
And (emphasis mine):
field1, field2: The names of the fields that are joined. The fields must be of the same data type and contain the same kind of data, but they do not need to have the same name.
It appears you can't even have hard-coded values in your join; you must specify the column name to join against.
In your case, you would want:
SELECT *
FROM Table1
LEFT JOIN (
SELECT DISTINCT TOP 1 ID
FROM Table2
ORDER BY ID
) Table2Derived ON Table1.ID = Table2Derived.ID

Are "from Table1 left join Table2" and "from Table2 right join Table1" interchangeable?

For example, there are two tables:
create table Table1 (id int, Name varchar (10))
create table Table2 (id int, Name varchar (10))
Table1 data as follows:
Id Name
-------------
1 A
2 B
Table2 data as follows:
Id Name
-------------
1 A
2 B
3 C
If I execute both below mentioned SQL statements, both outputs will be the same:
select *
from Table1
left join Table2 on Table1.id = Table2.id
select *
from Table2
right join Table1 on Table1.id = Table2.id
Please explain the difference between left and right join in the above SQL statements.
Select * from Table1 left join Table2 ...
and
Select * from Table2 right join Table1 ...
are indeed completely interchangeable. Try however Table2 left join Table1 (or its identical pair, Table1 right join Table2) to see a difference. This query should give you more rows, since Table2 contains a row with an id which is not present in Table1.
Table from which you are taking data is 'LEFT'.
Table you are joining is 'RIGHT'.
LEFT JOIN: Take all items from left table AND (only) matching items from right table.
RIGHT JOIN: Take all items from right table AND (only) matching items from left table.
So:
Select * from Table1 left join Table2 on Table1.id = Table2.id
gives:
Id Name
-------------
1 A
2 B
but:
Select * from Table1 right join Table2 on Table1.id = Table2.id
gives:
Id Name
-------------
1 A
2 B
3 C
you were right joining table with less rows on table with more rows
AND
again, left joining table with less rows on table with more rows
Try:
If Table1.Rows.Count > Table2.Rows.Count Then
' Left Join
Else
' Right Join
End If
You seem to be asking, "If I can rewrite a RIGHT OUTER JOIN using LEFT OUTER JOIN syntax then why have a RIGHT OUTER JOIN syntax at all?" I think the answer to this question is, because the designers of the language didn't want to place such a restriction on users (and I think they would have been criticized if they did), which would force users to change the order of tables in the FROM clause in some circumstances when merely changing the join type.
select fields
from tableA --left
left join tableB --right
on tableA.key = tableB.key
The table in the from in this example tableA, is on the left side of relation.
tableA <- tableB
[left]------[right]
So if you want to take all rows from the left table (tableA), even if there are no matches in the right table (tableB), you'll use the "left join".
And if you want to take all rows from the right table (tableB), even if there are no matches in the left table (tableA), you will use the right join.
Thus, the following query is equivalent to that used above.
select fields
from tableB
right join tableA on tableB.key = tableA.key
Your two statements are equivalent.
Most people only use LEFT JOIN since it seems more intuitive, and it's universal syntax - I don't think all RDBMS support RIGHT JOIN.
I feel we may require AND condition in where clause of last figure of Outer Excluding JOIN so that we get the desired result of A Union B Minus A Interaction B.
I feel query needs to be updated to
SELECT <select_list>
FROM Table_A A
FULL OUTER JOIN Table_B B
ON A.Key = B.Key
WHERE A.Key IS NULL AND B.Key IS NULL
If we use OR , then we will get all the results of A Union B
select *
from Table1
left join Table2 on Table1.id = Table2.id
In the first query Left join compares left-sided table table1 to right-sided table table2.
In Which all the properties of table1 will be shown, whereas in table2 only those properties will be shown in which condition get true.
select *
from Table2
right join Table1 on Table1.id = Table2.id
In the first query Right join compares right-sided table table1 to left-sided table table2.
In Which all the properties of table1 will be shown, whereas in table2 only those properties will be shown in which condition get true.
Both queries will give the same result because the order of table declaration in query are different like you are declaring table1 and table2 in left and right respectively in first left join query, and also declaring table1 and table2 in right and left respectively in second right join query.
This is the reason why you are getting the same result in both queries. So if you want different result then execute this two queries respectively,
select *
from Table1
left join Table2 on Table1.id = Table2.id
select *
from Table1
right join Table2 on Table1.id = Table2.id
Select * from Table1 t1 Left Join Table2 t2 on t1.id=t2.id
By definition: Left Join selects all columns mentioned with the "select" keyword from Table 1 and the columns from Table 2 which matches the criteria after the "on" keyword.
Similarly,By definition: Right Join selects all columns mentioned with the "select" keyword from Table 2 and the columns from Table 1 which matches the criteria after the "on" keyword.
Referring to your question, id's in both the tables are compared with all the columns needed to be thrown in the output. So, ids 1 and 2 are common in the both the tables and as a result in the result you will have four columns with id and name columns from first and second tables in order.
*select *
from Table1
left join Table2 on Table1.id = Table2.id
The above expression,it takes all the records (rows) from table 1 and columns, with matching id's from table 1 and table 2, from table 2.
select *
from Table2
right join Table1 on Table1.id = Table2.id**
Similarly from the above expression,it takes all the records (rows) from table 1 and columns, with matching id's from table 1 and table 2, from table 2. (remember, this is a right join so all the columns from table2 and not from table1 will be considered).