仅当值不存在时才返回行

我有2桌 – 预订:

id | some_other_column ----+------------------ 1 | value 2 | value 3 | value 

和第二个表 – reservation_log:

  id | reservation_id | change_type ----+----------------+------------- 1 | 1 | create 2 | 2 | create 3 | 3 | create 4 | 1 | cancel 5 | 2 | cancel 

我只需要select未取消的预订(在本例中只有ID 3)。 我可以很容易地select取消与一个简单的“WHERE change_type =取消”条件,但我努力与NOT取消,因为简单的WHERE在这里不工作。

 SELECT * FROM reservation WHERE id NOT IN (select reservation_id FROM reservation_log WHERE change_type = 'cancel') 

要么:

 SELECT r.* FROM reservation r LEFT JOIN reservation_log l ON r.id = l.reservation_id AND l.change_type = 'cancel' WHERE l.id IS NULL 

第一个版本更直观,但我认为第二个版本通常会获得更好的性能(假设您在连接中使用的列上有索引)。

第二个版本的工作原理是因为LEFT JOIN为第一个表中的所有行返回一行。 当ON条件成功时,这些行将包含第二个表中的列,就像INNER JOIN 。 当条件失败时,返回的行将为第二个表中的所有列包含NULLWHERE l.id IS NULLtesting然后匹配那些行,所以它find表之间没有匹配的所有行。

为了完整性(我真的相信它更合适),我鼓励你使用一个简单的NOT EXISTS

 SELECT * FROM reservation R WHERE NOT EXISTS ( SELECT 1 FROM reservation_log WHERE reservation_id = R.id AND change_type = 'cancel' );