Я бы использовал агрегацию:
select o.customer_id
from orders o
group by o.customer_id
having sum( (product = 'Widget 1') ) > 0 and
sum( (product = 'Widget 3') ) > 0 and
sum( (product not in ('Widget 1', 'Widget 3')) );
Не вижу смысла возвращать сами продукты, но вы можете добавить group_concat(product)
, если действительно хотите.
Если вы хотите исходные строки, вы можете использовать выше для фильтрации. Или:
select o.*
from orders o
where o.product in ('Widget 1', 'Widget 3') and
not exists (select 1
from orders o2
where o2.customer_id = o.customer_id and
o2.product not in ('Widget 1', 'Widget 3')
);