Выборка по значениям из дочерней таблицы

scorpion-ds

Новичок
Разрабатываю фильтрацию товара, простыми полями цены, брендов, возраста (не без помощи ...) вроде разобрался, сейчас стоит вопрос по фильтрации товаров по их характеристикам.

Таблица товаров:
Код:
CREATE TABLE `cs_eshop_product` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `content` longtext COLLATE utf8_unicode_ci,
  `enabled` tinyint(1) DEFAULT '1',
  `created` datetime DEFAULT NULL,
  `updated` datetime DEFAULT NULL,
  `published` datetime DEFAULT NULL,
  `announcement` longtext COLLATE utf8_unicode_ci,
  `slug` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `seo_title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `seo_description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `seo_keywords` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `price` double NOT NULL DEFAULT '0',
  `category_id` int(11) DEFAULT NULL,
  `image` int(11) DEFAULT NULL,
  `gender` varchar(1) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'u',
  `age_min` smallint(6) NOT NULL DEFAULT '0',
  `age_max` smallint(6) NOT NULL DEFAULT '16',
  `brand_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_22FC563B12469DE2` (`category_id`),
  KEY `IDX_22FC563BC53D045F` (`image`),
  KEY `IDX_22FC563B44F5D008` (`brand_id`),
  CONSTRAINT `FK_22FC563B12469DE2` FOREIGN KEY (`category_id`) REFERENCES `cs_taxonomy_category` (`id`),
  CONSTRAINT `FK_22FC563B44F5D008` FOREIGN KEY (`brand_id`) REFERENCES `cs_eshop_brand` (`id`),
  CONSTRAINT `FK_22FC563BC53D045F` FOREIGN KEY (`image`) REFERENCES `media__media` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11215 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Таблица свойств:
Код:
CREATE TABLE `cs_eshop_property` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
  `enabled` tinyint(1) DEFAULT '1',
  `position` int(11) DEFAULT NULL,
  `filter` tinyint(1) DEFAULT '0',
  `slug` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Таблица значений свойств:
Код:
CREATE TABLE `cs_eshop_property_value` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `property_id` int(11) DEFAULT NULL,
  `product_id` int(11) DEFAULT NULL,
  `value` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `position` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_B767FFB5549213EC` (`property_id`),
  KEY `IDX_B767FFB54584665A` (`product_id`),
  CONSTRAINT `FK_B767FFB54584665A` FOREIGN KEY (`product_id`) REFERENCES `cs_eshop_product` (`id`),
  CONSTRAINT `FK_B767FFB5549213EC` FOREIGN KEY (`property_id`) REFERENCES `cs_eshop_property` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8198 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Простой запрос:
Код:
SELECT c0_.id AS id0, c0_.title AS title1, c3_.id, c3_.slug, c2_.id, c2_.value FROM cs_eshop_product c0_ LEFT JOIN cs_eshop_brand c1_ ON (c1_.id = c0_.brand_id) LEFT JOIN cs_eshop_property_value c2_ ON (c2_.product_id = c0_.id) LEFT JOIN cs_eshop_property c3_ ON (c2_.property_id = c3_.id)
WHERE
c0_.category_id IN (21)

GROUP BY c0_.id
ORDER BY c0_.id DESC
Вернет товары из категории 21.

Теперь добавляем фильтрацию по одному из свойств:
Код:
SELECT c0_.id AS id0, c0_.title AS title1, c3_.id, c3_.slug, c2_.id, c2_.value FROM cs_eshop_product c0_ LEFT JOIN cs_eshop_brand c1_ ON (c1_.id = c0_.brand_id) LEFT JOIN cs_eshop_property_value c2_ ON (c2_.product_id = c0_.id) LEFT JOIN cs_eshop_property c3_ ON (c2_.property_id = c3_.id)
WHERE
c0_.category_id IN (21)
AND (
    (c3_.slug = 'tip' AND c2_.value IN ('P7=1', 'P7=2'))
   
)
ORDER BY c0_.id DESC
Вернет все товары у которых выбрано свойство 'P7=1', 'P7=2'.

Но так как в фильтре может быть несколько свойств, то необходимо обеспечить фильтрацию по нескольким свойствам:
Код:
SELECT c0_.id AS id0, c0_.title AS title1, c3_.id, c3_.slug, c2_.id, c2_.value FROM cs_eshop_product c0_ LEFT JOIN cs_eshop_brand c1_ ON (c1_.id = c0_.brand_id) LEFT JOIN cs_eshop_property_value c2_ ON (c2_.product_id = c0_.id) LEFT JOIN cs_eshop_property c3_ ON (c2_.property_id = c3_.id)
WHERE
c0_.category_id IN (21)
AND (
    (c3_.slug = 'tip' AND c2_.value IN ('P7=1', 'P7=2'))
    AND
    (c3_.slug = 'material' AND c2_.value IN ('P3=1'))
)
ORDER BY c0_.id DESC
Такой запрос не возвращает ни каких результатов, хотя если задавать отдельно "(c3_.slug = 'tip' AND c2_.value IN ('P7=1', 'P7=2'))" или "(c3_.slug = 'material' AND c2_.value IN ('P3=1'))", то результаты есть.

Как правильно составить условие для получения записей одновременно по двум условиям?
 

scorpion-ds

Новичок
Код:
SELECT c0_.id AS id0, c0_.title AS title1, COUNT(c0_.id) as prod_count, c3_.id, c3_.slug, c2_.id, c2_.value FROM cs_eshop_product c0_ LEFT JOIN cs_eshop_brand c1_ ON (c1_.id = c0_.brand_id) LEFT JOIN cs_eshop_property_value c2_ ON (c2_.product_id = c0_.id) LEFT JOIN cs_eshop_property c3_ ON (c2_.property_id = c3_.id)
WHERE
c0_.category_id IN (21)
AND (
    (c3_.slug = 'tip' AND c2_.value IN ('тестовый', 'P7=1'))
    OR
    (c3_.slug = 'material' AND c2_.value IN ('пластик'))
)
GROUP BY c0_.id   
HAVING
    prod_count = 2
ORDER BY c0_.id DESC
Будет ли такое условие правильным? На первый взгляд оно работает, но кажется не очень красивым.

Я заменил AND на OR между условиями по характеристикам, при этом в результате дополнительно отсеиваю те записи которые встретились меньше, чем количество свойств, в данном случае "2".
 
Сверху