简体   繁体   中英

SQL join - How to select all the distinct values that appear in one table and not another

I have 2 SQL tables. The 2 tables share 2 columns: external_id of type int and permission of type text :

CREATE TABLE A (
    id              serial PRIMARY KEY,
    external_id     int,
    permission      text,          
    something       int,           
    rather          text
);

CREATE TABLE B (
    id              serial PRIMARY KEY,
    external_id     int,
    permission      text,          
    random          int,           
    life_story      text
);

I want to select all the distinct combinations of external_id , permission in table A that DO NOT exist in table B AND vice-versa, all the distinct combinations of external_id , permission in table B that DO NOT exist in table A

To clarify the query I'm trying to write, I turn to examples: If the tables look like this:

mwe=# select * from A;
 id | external_id | permission | something | rather
----+-------------+------------+-----------+---------
  1 |           1 | X          |      1111 | bla bla
  2 |           1 | P          |      1111 | bla bla
  3 |           2 | X          |      1111 | bla bla
(3 rows)

mwe=# select * from B;
 id | external_id | permission | random | life_story
----+-------------+------------+--------+------------
  1 |           1 | X          |     41 | bla bla
  2 |           1 | P          |     15 | bla bla
  3 |           2 | X          |     46 | bla bla
(3 rows)

The result of my query will be empty. because the distinct external_id , permission tuples for both tables are:

1| X
1| P
2| X

If the state of the tables is:

mwe=# select * from A;
 id | external_id | permission | something | rather
----+-------------+------------+-----------+---------
  1 |           1 | X          |      1111 | bla bla
  2 |           1 | P          |      1111 | bla bla
  3 |           2 | P          |      1111 | bla bla
  4 |           2 | X          |      1111 | bla bla
  5 |           2 | X          |      2222 | bla bla
(5 rows)

mwe=# select * from B;
 id | external_id | permission | random | life_story
----+-------------+------------+--------+------------
  1 |           1 | X          |     41 | bla bla
  2 |           1 | X          |     99 | one day along time ago
  3 |           1 | P          |     15 | bla bla
  4 |        NULL | X          |     46 | bla bla
  5 |           2 | X          |     46 | bla bla
(5 rows)

the result of my query should be:

2   | P
NULL| X

because the distinct external_id , permission tuples for table A are:

 1| X              # id=1
 1| P              # id=2
 2| P              # id=3
 2| X              # id=4,5

and the distinct external_id , permission tuples for table B are:

 1   | X           # id=1,2
 1   | P           # id=3
 NULL| X           # id=4
 2   | X           # id=5

since 2| P 2| P appears in the tuples we listed for table A and does NOT appear in the tuples we listed for table B , I want it to be returned as a result of my desired select query.

And since NULL| X NULL| X appears in the tuples we listed for table B and does NOT appear in the tuples we listed for table A , I want it to be returned as a result of my desired select query

For every other distinct external_id , permission tuples in any of the two tables, there is a matching tuple on the other table:

 1   | X           # table A id=1 table B id=1,2
 1   | P           # table A id=2 table B id=3
 2   | X           # table A id=4,5 table B id=5

I'm using Postgres 9.6

You can use NOT IN on each side, and then UNION both sides:

select distinct external_id, permission
  from a
  where (external_id, permission) not in (
    select external_id, permission from b
  )
  or external_id is null and permission not in (
    select permission from b where permission is null    
  )
union  
select distinct external_id, permission
  from b
  where (external_id, permission) not in (
    select external_id, permission from a
  )
  or external_id is null and permission not in (
    select permission from a where permission is null    
  );

Result:

external_id  permission
-----------  ----------
2            P         
<null>       X         

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