user655145
user655145

Reputation:

SQL Query: Joining two tables where entity of the first table has no, or multiple entries in other table

I have to database tables, where entities of the first Table may or may not have associated entries in the second table:

Table 1          Table 2       
+-----+-----+    +-----+-------+-------+
| ID  | ... |    | ID  | T1_ID | NAME  |
+-----+-----+    +-----+-------+-------+
|  1  | ... |    |  1  |   1   |  p1   |
|  2  | ... |    |  2  |   1   |  p2   |
|  3  | ... |    |  3  |   2   |  p1   |
|  4  | ... |    +-----+-------+-------+
+-----+-----+

I have the following queries i need to run:

  1. Get all entities of Table_1 with a specific entry of Table_2 - That's easy, a simple Join will do...

  2. Get all entities of Table_1, which don't have a specific entry of Table_2 associated - not so easy, but i also managed to query this with a join.

  3. Get all entities of Table_1, which have a specific entry (A) and don't have another specific entry (B) associated, i.e. get all entities of Table_1 that have an entity of Table_2 with name=p1 and don't have an entity of Table_2 with name=p2 associated.

Is it possible to accomplish the kind of query from (3) in a single sql-statement without a sub-query?

Upvotes: 0

Views: 9590

Answers (4)

ean5533
ean5533

Reputation: 8994

Get all entities of Table_1, which have a specific entry (A) and don't have another specific entry (B) associated, i.e. get all entities of Table_1 that have an entity of Table_2 with name=p1 and don't have an entity of Table_2 with name=p2 associated.

I'm having a bit of trouble understanding your criteria, but I think that is what you want:

SELECT * 
FROM Table1 t1 
JOIN Table2 t2 ON t1.ID = t2.t1_id 
WHERE t2.name = 'p1' 
AND NOT EXISTS(SELECT 'x' FROM Table2 t2_2 WHERE t1.ID = t2_2.t1_id AND t2_2.name = 'p2')

That will give you everything from Table1 that has a matching record in Table2 with name = 'p1' and DOESN'T have a matching record in Table2 with name = 'p2'. Is that what you need?

EDIT AGAIN:

I thought of a smarter way to do this that involves a static (non-correlated) subquery. This subquery will only be executed one time, rather than being executed once for every parent row in Table1. I didn't put this code through a query analyzer, but it should be significantly faster than of the queries using EXISTS(...)

SELECT * 
FROM Table1 t1 
JOIN Table2 t2 ON t1.ID = t2.t1_id 
WHERE t2.name = 'p1' 
AND t1.id NOT IN(SELECT t1_id FROM Table2 WHERE name = 'p2')

Upvotes: 4

Andriy M
Andriy M

Reputation: 77667

To make the variation of solutions more complete:

SELECT t1.*
FROM Table_1 t1
  INNER JOIN Table_2 it2 ON t1.ID = it2.T1_ID AND it2.NAME = 'p1'
  LEFT JOIN Table_2 lt2  ON t1.ID = lt2.T1_ID AND lt2.NAME = 'p2'
WHERE lt2.ID IS NULL

Upvotes: 0

Tim Rogers
Tim Rogers

Reputation: 21713

You can use an EXISTS subquery (effectively the same as doing two joins).

SELECT * FROM Table_1 AS t1
WHERE EXISTS (SELECT * FROM Table_2 AS t2 WHERE t1.Id = t2.Id AND Name='p1')
AND NOT EXISTS (SELECT * FROM Table_2 AS t2 WHERE t1.Id = t2.Id AND Name='p2')

Upvotes: 3

Johan
Johan

Reputation: 76547

To get all occurrences where t2 matches t1.id but not some other field do

SELECT t1.id, t2.id FROM table2 t2
INNER JOIN table1 t1 ON (t2.t1_id = t1.id AND not(t2.fieldx <=> t1.fieldx))

Note that this will also exclude rows where both fieldx are null.
If you don't want that substitute the <=> with =.

Upvotes: 0

Related Questions