"В его личном деле было написано - ОСОБЫЕ ПРИМЕТЫ - все" (Dellamorte Dellamore)
1) Мне кажется, что вам стоит серьезно переработать структуру БД
2) Перефразируем ваш запрос:
SELECT *
FROM products p
WHERE p.id IN
(SELECT DISTINCT pc.product_id
FROM product_characteristic pc
WHERE pc.product_id = p.id
AND pc.characteristic_id= ANY (2, 19, 20)
AND pc.selected_option_id=ANY (129, 2001569, 2001570, 2001571)
)
Или, "совсем по русски"
SELECT *
FROM products p
WHERE p.id IN
(SELECT DISTINCT pc.product_id
FROM product_characteristic pc
WHERE pc.product_id = p.id
AND (pc.characteristic_id =2 OR pc.characteristic_id =19 or pc.characteristic_id =20)
AND (pc.selected_option=129 OR pc.selected_option=2001569 OR pc.selected_option=2001570 or pc.selected_option=2001571)
)
То есть вместо пересечения характеристик, вы выбираете их объединение
Ну и, поскольку подзапрос вообще говоря самостоятелен, и независим от внешнего запроса, я не очень понимаю, что у вас в нем делает p.id и как оно вообще будет работать.
3) Если попробовать написать то, что вы хотели, получится примерно следующее
SELECT *
FROM products p
WHERE p.id IN
(SELECT pc.product_id
FROM product_characteristic pc, product_characteristic pc1,product_characteristic pc2,
WHERE pc.product_id=pc1.product_id and pc.product_id=pc2.product_id
AND pc.characteristic=2 AND pc.selected_option_id=129
AND pc1.characteristic=19 AND pc1.selected_option_id=2001569
AND pc2.characteristic=20 AND pc2.selected_option_id in (2001570, 2001571)
)
Во-первых - убираем DISTINCT из подзапроса - он даст нам перечень product_id, и даже если они будут повторяться, основной запрос выберет только уникальные строки
Во вторых - добавляем еще два псевдонима к таблице product_characteristic
для каждого псевдонима ставим свое условие по id характеристики и id выбранной опции
Ну и сообщаем, что искомый product_id для всех таблиц product_characteristic у вас одинаковый.
Если у вас selected_option_id уникален для каждой опции, можно исключить из запроса поле selected_option_id
тогда получится примерно так:
SELECT *
FROM products p
WHERE p.id IN
(SELECT pc.product_id
FROM product_characteristic pc, product_characteristic pc1,product_characteristic pc2,
WHERE pc.product_id=pc1.product_id and pc.product_id=pc2.product_id
AND pc.selected_option_id=129
AND pc1.selected_option_id=2001569
AND pc2.selected_option_id in (2001570, 2001571)
)