Выберите строки, не имеющие определенных записей в истории

#sql #sql-server

Вопрос:

У меня есть 2 стола:

Таблица устройств

  ---------- ---------- 
| DeviceId | Name     |
 ---------- ---------- 
|        10| Dev10    |
|        20| Dev20    |
|        30| Dev30    |
 ---------- ---------- 
 

Таблица истории

  ---------- ------- --------------------- 
| DeviceId | State |      TimeStamp      |
 ---------- ------- --------------------- 
|        10|     0 | 06/09/2021 11:10:01 |
|        20|     1 | 06/09/2021 11:10:02 |
|        30|     0 | 06/09/2021 11:10:03 |
|        10|     0 | 06/09/2021 11:10:04 |
|        20|     0 | 06/09/2021 11:10:05 |
|        30|     1 | 06/09/2021 11:10:05 |
|        10|     2 | 06/09/2021 11:10:06 |
|        20|     0 | 06/09/2021 11:10:06 |
|        30|     0 | 06/09/2021 11:10:06 |
 ---------- ------- --------------------- 
 

Я могу выбрать идентификаторы устройств, которые когда-либо были в состоянии=2

 SELECT *
FROM Device A
CROSS APPLY (SELECT TOP 1 * 
             FROM History B
             WHERE A.ID = B.DeviceId and B.[State]=2
             ORDER BY B.TimeStamp DESC) as B
order by A.Id
 

Вопрос в том, как выбрать устройства, которые никогда не были в состоянии=2.

Результат должен быть:

  ---------- ---------- 
| DeviceId | Name     |
 ---------- ---------- 
|        20| Dev20    |
|        30| Dev30    |
 ---------- ---------- 
 

Комментарии:

1. where not exists (select * from history where deviceID = a.deviceId and state = 2) . Хотя обычно я предпочитаю что-то вроде left join History h on h.deviceId = a.deviceId and h.state = 2 where h.deviceId is null

Ответ №1:

Вы хотите знать, чего не существует, естественный синтаксис заключается в использовании exists

 select *
from Device d
where not exists (
  select * 
  from History h 
  where h.DeviceId = d.DeviceId and h.state = 2
)