Conceptual question: Does left join with not null filter on the joining key always equal to inner join? - sql

This is a conceptual question. So I dont have any actual code. But it is simple to follow.
Lets stay we have two tables (Join_1 and Join_2) from joining A and B:
Join_1:
Select *
From A join B on A.id = B.id
Join_2
Select *
From A left join B on A.id = B.id
where B.id is not null
Question: Does Join_1 always equal to Join_2? You can think of any conditions such as null values, duplicates and so on.

For all practical purposes, "yes".
The only exception would be if a.id could be NULL. In that case, the first version would filter out those rows. The second would include them.

Related

In JPQL, in case of left joins, is there any difference when we give a particular condition in ON clause or in where clause?

Is there any difference in these two queries in terms of processing and data obtained:
SELECT * from Table A Inner JOIN Table B ON A.id = B.id
LEFT JOIN Table B ON A.id = C.id AND (C.status IS NULL OR C.status <>3)
WHERE A.status = 1 and B.status = 1
OR
SELECT * from Table A Inner JOIN Table B ON A.id = B.id
LEFT JOIN Table B ON A.id = C.id
WHERE A.status = 1 and B.status = 1 AND (C.status IS NULL OR C.status <>3)
After a deep dive into left joins and different clauses, Here is what I have came up:
1) When to use where and on clauses in case of joins:
In case of inner joins, it really does not matter where you give your conditions in where clause or on clause. Giving conditions in where clause will be used to filtering the data and giving the conditions in on clause will be to used to join the table. For readability purpose it is good to provide the filtering conditions in where clause only just to make sure you convince your intent through your query. But here is the catch, the query plan will change depending on where you pass your conditions and can heavily affect you.
In case of outer joins(left, right, full) passing conditions blindly in where and on clause can give you incorrect data.
2) When Left Join(or any outer join) can start behaving like inner joins
Be careful when you specify filtering conditions for null values in where clause. Suppose you have two tables: Users and orders and you want irrespective of whether they have placed order or not, so we chose left join. Further we have condition to filter condition like noOfOrders > 3, but since it was a left join values where null in products table. All null values will be filtered out, since null<0, hence left join will behave like an inner join.

Filter on the column on which two tables are joined

Are next two queries going to return same result set?
SELECT * FROM tableA a
JOIN tableB b
ON a.id = b.id
WHERE a.id = '5'
--------------------------------
SELECT * FROM tableA a
JOIN tableb b
ON a.id = b.id
WHERE b.id = '5'
Also, will answer be different if LEFT JOIN is used instead of JOIN?
As written, they will return the same result.
The two will not necessarily return the same result with a left join.
Yes the result will be the same.
With a left join you will get every dataset of both table who got a ID.
With a join (Inner Join) you will get only the dataset's who a.id = b.id.
This site will explain you how to join https://www.w3schools.com/sql/sql_join.asp
Yes they will. A simple join works like an inner join by default. It checks for instances where the item you're joining on exist on both tables. Since you're joining on where a.id=b.id the results will be the same.
If you change the type of join to a left, the results will include all a.id's regardless of whether they are equal to 5.

SQL trying to do a JOIN to include results from multiple Tables

I'm a complete novice teaching myself SQL by writing and modifying a few queries and reports at work.
I've got something of a handle on the various types of JOINs and I've used INNER JOIN a few times with decent success.
What I'm stuck on should be a simple task, but my Google-Fu must be weak. Here's what I'm trying to do.
Say I have 3 tables, Table_A, Table_B, and Table_C, and each table has a column called [Serial_Number].
What I'm wanting to select is 3 of the other columns if A.Serial_Number = B.Serial_Number OR C.Serial_Number.
I've tried doing:
SELECT
*
FROM
Table_A AS A
INNER JOIN Table_B AS B ON A.Serial_Number = B.Serial_Number
INNER JOIN Table_C AS C ON A.Serial_Number = C.Serial_Number
But this always yields 0 results as the nature of the data dictates that if A matches B, it will never match C and vice versa. I also tried a LEFT OUTER JOIN as the second clause, but this just includes NULLs from Table_C that have already matched on Table_B.
All the searches I have done relating to JOINs on multiple tables seem to be about using JOINS to further exclude records, where I'm actually wanting to INCLUDE more records.
Like I said, I'm sure this is really simple, just needing a nudge in right direction.
Thanks!
The use of two inner joins here is akin to saying
If A.Serial_Number = B.Serial_Number AND
A.Serial_Number = C.Serial_Number
Using left outer join on the second clause - by which i presume you mean second join - would perform a left join on a result set already filtered by A.Serial_Number = B.Serial_Number by the first inner join. Given that B.Serial_Number doesn't relate to C.Serial_Number you wouldn't expect the an equijoin to return any result from tablec.
What you want is a left outer join like you tried but for both tableb and tablec.
Select *
From tablea
Left join tableb on tableb.Serial_Number = tablea.Serial_Number
Left join tablec on tablec.Serial_Number = tablea.Serial_Number
This way regardless of whether tablea.Serial_Number is in tableb it will still be returned and thus available to be joined to tablec
Agreed. Your output for your inner joins is producing NULLs which is why it is resulting in 0. I would suggest modifying your INNER JOIN.

How to make a one to one left outer join?

I was wondering, is there a way to make a kind of one to one left outer join:
I need a join that matches say table A with table B, for each record on table A it must search for its pair on table B, but there exists only 1 record that matches that condition, so when it has found its pair on B, it must stop and continue with the next row at table A.
What I have is a simple LEFT OUTER JOIN.
select * from A left outer join B on A.ID = B.ID order by (NAME) asc
Thanks in advance!
SQL doesn't work this way. In the first place it does not look at things row-by-row. In the second place what defines the record you want to match on?
Assuming you don't really care which row is selcted, something like this might work:
SELECT *
From tableA
left outer join
(select b.* from tableb b1
join (Select min(Id) from tableb group by id) b2 on b1.id - b2.id) b
on a.id = b.id
BUt it still is pretty iffy that you wil get the records you want when there are multiple records with the id in table b.
The syntax you present in your question is correct. There is no difference in the query for joining on a one-to-one relationship than on a one-to-many.

How can I implement SQL INTERSECT and MINUS operations in MS Access

I have researched and haven't found a way to run INTERSECT and MINUS operations in MS Access. Does any way exist
INTERSECT is an inner join. MINUS is an outer join, where you choose only the records that don't exist in the other table.
INTERSECT
select distinct
a.*
from
a
inner join b on a.id = b.id
MINUS
select distinct
a.*
from
a
left outer join b on a.id = b.id
where
b.id is null
If you edit your original question and post some sample data then an example can be given.
EDIT: Forgot to add in the distinct to the queries.
INTERSECT is NOT an INNER JOIN. They're different. An INNER JOIN will give you duplicate rows in cases where INTERSECT WILL not. You can get equivalent results by:
SELECT DISTINCT a.*
FROM a
INNER JOIN b
on a.PK = b.PK
Note that PK must be the primary key column or columns. If there is no PK on the table (BAD!), you must write it like so:
SELECT DISTINCT a.*
FROM a
INNER JOIN b
ON a.Col1 = b.Col1
AND a.Col2 = b.Col2
AND a.Col3 = b.Col3 ...
With MINUS, you can do the same thing, but with a LEFT JOIN, and a WHERE condition checking for null on one of table b's non-nullable columns (preferably the primary key).
SELECT DISTINCT a.*
FROM a
LEFT JOIN b
on a.PK = b.PK
WHERE b.PK IS NULL
That should do it.
They're done through JOINs. The old fashioned way :)
For INTERSECT, you can use an INNER JOIN. Pretty straightforward. Just need to use a GROUP BY or DISTINCT if you have don't have a pure one-to-one relationship going on. Otherwise, as others had mentioned, you can get more results than you'd expect.
For MINUS, you can use a LEFT JOIN and use the WHERE to limit it so you're only getting back rows from your main table that don't have a match with the LEFT JOINed table.
Easy peasy.
Unfortunately MINUS is not supported in MS Access - one workaround would be to create three queries, one with the full dataset, one that pulls the rows you want to filter out, and a third that left joins the two tables and only pulls records that only exist in your full dataset.
Same thing goes for INTERSECT, except you would be doing it via an inner join and only returning records that exist in both.
No MINUS in Access, but you can use a subquery.
SELECT DISTINCT a.*
FROM a
WHERE a.PK NOT IN (SELECT DISTINCT b.pk FROM b)
I believe this one does the MINUS
SELECT DISTINCT
a.CustomerID,
b.CustomerID
FROM
tblCustomers a
LEFT JOIN
[Copy Of tblCustomers] b
ON
a.CustomerID = b.CustomerID
WHERE
b.CustomerID IS NULL