Часть «не запущена» в таблице фильтров ваших запросов B, вплоть до следующего:
+----+-----------+----------+
| id | parent_id | status |
+----+-----------+----------+
| 2 | 2 | stopped |
| 3 | 1 | stopped |
| 4 | 1 | stopped |
+----+-----------+----------+
Затем ваше объединение ищет строки, в которых идентификатор из таблицы А совпадает с родительским идентификатором таблицы B, что и является возвращается правильно (но не считая 1 дважды)
Если вы хотите, чтобы первая половина вернулась:
+----+-----------+----------+
| id | parent_id | status |
+----+-----------+----------+
| 2 | 2 | stopped |
+----+-----------+----------+
PLUS the rows from table A not referred to in table B....
Тогда ответ GMB выше верен -
select a.id
from a
where not exists (select 1 from b where b.parent_id = a.id and b.status = 'started')
Вот скрипка https://sqltest.net/#1005425
Однако, как и предполагалось, в таблице B вы, скорее всего, столкнетесь с большим количеством ненужного дублирования - многие строки будут начинаться и останавливаться, необязательно в хронологическом порядке (например, - первая запись для A.id = 1 предполагала, что она была начата, 3-я и 4-я записи (предположительно введенные впоследствии) остановили ее, но вы исключили бы эту запись для запуска.
Почему бы не изменить свою таблицу структура для обновления одной строки?