0

Apology in advance for a long question, but doing this just for the sake of learning: i'm new to SQL and researching on JOIN for now. I'm getting two different behaviors when using INNER and OUTER JOIN. What I know is, INNER JOIN gives an intersection kind of result while returning only common rows among tables, and (LEFT/RIGHT) OUTER JOIN is outputting what is common and remaining rows in LEFT or RIGHT tables, depending upon LEFT/RIGHT clause respectively.

While working with MS Training Kit and trying to solve this practice: "Practice 2: In this practice, you identify rows that appear in one table but have no matches in another. You are given a task to return the IDs of employees from the HR.Employees table who did not handle orders (in the Sales.Orders table) on February 12, 2008. Write three different solutions using the following: joins, subqueries, and set operators. To verify the validity of your solution, you are supposed to return employeeIDs: 1, 2, 3, 5, 7, and 9."

I'm successful doing this with subqueries and set operators but with JOIN is returning something not expected. I've written the following query:

USE TSQL2012;
SELECT
    E.empid
FROM
    HR.Employees AS H
    JOIN Sales.Orders AS O
        ON H.empid = O.empid
        AND O.orderdate = '20080212'
    JOIN HR.Employees AS E
        ON E.empid <> H.empid

ORDER BY
    E.empid
;

I'm expecting results as: 1, 2, 3, 5, 7, and 9 (6 rows) But what i'm getting is: 1,1,1,2,2,2,3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,9,9,9 (24 rows)

I tried some videos but could not understand this side of INNER/OUTER JOIN. I'll be grateful if someone could help this side of JOIN, why is it so and what should I try to understand while working with JOIN.

2

4 Answers 4

2

you can also use left outer join to get not matching

*** The LEFT JOIN keyword returns all rows from the left table (table1), with the matching rows in the right table (table2). The result is NULL in the right side when there is no match.

SELECT
    H.empid
FROM
    HR.Employees AS H
    LEFT OUTER JOIN Sales.Orders AS O
        ON H.empid = O.empid
        AND O.orderdate = '20080212'
 WHERE O.empid IS NULL    

Above script will return emp id who did not handle orders on specify date

2

here you can see all kind of join

enter image description here

Diagram taken from: http://dsin.wordpress.com/2013/03/16/sql-join-cheat-sheet/

adjust your query to be like this

   USE TSQL2012;
SELECT
    E.empid
FROM
    HR.Employees AS H
    JOIN Sales.Orders AS O
        ON H.empid = O.empid
        where O.orderdate = '2008-02-12' AND O.empid IN null
   ORDER BY
    E.empid
;
2
  • reference dsin.wordpress.com/2013/03/16/sql-join-cheat-sheet/ Commented Nov 14, 2014 at 8:36
  • Such Venn-like diagrams for joins are unhelpful & misleading. All you have to do to see this is try to write a correct legend for one. Don't forget that SQL tables are bags not sets. Joins are on any condition & don't need constraints so at best the diagrams when explained address special cases and/or partial properties.
    – philipxy
    Commented Feb 27, 2021 at 2:40
0
USE TSQL2012;

SELECT
   distinct E.empid
FROM
    HR.Employees AS H
    JOIN Sales.Orders AS O
        ON H.empid = O.empid
        AND O.orderdate = '20080212'
    JOIN HR.Employees AS E
        ON E.empid <> H.empid

ORDER BY
    E.empid
;
1
  • Thanks Manikanta, you just added DISTINCT in the query. It doesn't give the required result, it gives 1 - 9 all EMPID while i need who does not handled orders on specific dates (in question).
    – Khurram
    Commented Nov 14, 2014 at 7:00
0

Primary things to always remind yourself when working with SQL JOINs:

  1. INNER JOINs require a match in the join in order for result set rows produced prior to the INNER JOIN to remain in the result set. When no match is found for a row, the row is discarded from the result set.
  2. For a row fed to an INNER JOIN that matches to ONLY one row, only one copy of that row fed to the result set is delivered.
  3. For a row fed to an INNER JOIN that matches to multiple rows, the row will be delivered multiple times, once for each row match from the INNER JOIN table.
  4. OUTER JOINs will not discard rows fed to them in the result set, whether or not the OUTER JOIN results in a match or not.
  5. Just like INNER JOINs, if an OUTER JOIN matches to more than one row, it will increase the number of rows in the result set by duplicating rows equal to the number of rows matched from the OUTER JOIN table.

Ask yourself "if I get NO match on the JOIN, do I want the row discarded or not?" If the answer is NO, use an OUTER JOIN. If the answer is YES, use an INNER JOIN.

If you don't need to reference any of the columns from a JOIN table, don't perform a JOIN at all. Instead, use a WHERE EXISTS, WHERE NOT EXISTS, WHERE IN, WHERE NOT IN, etc. or similar, depending on your database engine in use. Don't rely on the database engine to be smart enough to discard unreferenced columns resulting from JOINs from the result set. Some databases may be smart enough to do that, some not. There's no reason to pull columns into a result set only to not reference them. Doing so increases chance of reduced performance.

Your JOIN of:

JOIN HR.Employees AS E
    ON E.empid <> H.empid

...is matching to all Employees rows with a DIFFERENT EMPID to all rows fed to that join. Use of NOT EQUAL on an INNER JOIN is a very rare thing to do or need, especially if the JOIN predicate is testing only ONE condition. That is why your getting duplicate rows in the result set.

On DB2, we could perform an EXCEPTION JOIN to accomplish that using a JOIN alone. Normally, on DB2, I would use a WHERE NOT EXISTS for that. On SQL Server you could do a JOIN to a query where the query set is all employees without orders in SALES.ORDERS on the specified date, but I don't know if that violates the rules of your tutorial.

Naveen posted the solution it appears your tutorial is looking for!

1
  • Naveen, Dudi and Mike... thank you for your answer. Now use of JOIN is very clear to me.
    – Khurram
    Commented Nov 14, 2014 at 12:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.