简体   繁体   中英

Left outer join doesn't exclude when both the table have null values

I have a requirement where I have to extract data exclusive to the left table. I am using the left outer join for this. But the output extract data that has a null value for the variable used in join condition in both the table which is not expected. Below is the detailed condition,

TableA

id name subject
1 tom math
2 jack null

TableB

id name subject
3 john science
2 jack null

Query

SELECT * 
  FROM TableA 
  LEFT JOIN TableB 
    ON a.id = b.id
   AND a.subject = b.subject
 WHERE b.id IS NULL
   AND b.subject IS NULL

Expected output

id name subject
1 tom math

Actual output

id name subject
1 tom math
2 jack null

The problem is that, in your problem requirement, you seem to need to treat null as equal to (other) null .

This goes against the definition of null . But you can achieve your required result - in the join condition, change

and a.subject = b.subject

to

and (a.subject = b.subject or (a.subject is null and b.subject is null))

In Oracle, you can do this more succintly:

and decode (a.subject, b.subject, 1) = 1

because decode was defined intentionally to see two null as "equal".

You could do the same for the id column, if needed - but assuming it's supposed to be primary key in both tables, you shouldn't need it.

EDIT The OP claims that the suggested use of decode produces the wrong result, while the explicit use of or (a.subject is null and b.subject is null) runs indefinitely on SQL Developer. So in this Edit I will show that the OP's claims are both wrong. (I ran everything on my copy of SQL Developer, so the IDE is not the issue.)

What he is doing, we don't know, but both suggestions are 100% correct for the data provided and the query as given to us (after we add the table aliases, which are missing in the OP's query, and we select just the data from TableA ).

Test data:

create table tablea (id, name, subject) as
  select 1, 'tom' , 'math'    from dual union all
  select 2, 'jack', null      from dual
;

create table tableb (id, name, subject) as
  select 3, 'john', 'science' from dual union all
  select 2, 'jack', null      from dual
;

First query and result:

SELECT a.* 
  FROM TableA a
  LEFT JOIN TableB b 
    ON a.id = b.id
   AND (a.subject = b.subject or (a.subject is null and b.subject is null))
 WHERE b.id IS NULL
   AND b.subject IS NULL
;

        ID NAME SUBJECT
---------- ---- -------
         1 tom  math

Second query and result:

SELECT a.* 
  FROM TableA a
  LEFT JOIN TableB b 
    ON a.id = b.id
   AND decode(a.subject, b.subject, 1) = 1
 WHERE b.id IS NULL
   AND b.subject IS NULL
;

        ID NAME SUBJECT
---------- ---- -------
         1 tom  math

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM