MySQL « Выборка строк из таблицы по нескольким значениям

Есть две таблицы,

с товарами
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .sql.geshi_code {font-family:monospace;} .sql.geshi_code .imp {font-weight: bold; color: red;} .sql.geshi_code .kw1 {color: #993333; font-weight: bold;} .sql.geshi_code .co1 {color: #808080; font-style: italic;} .sql.geshi_code .co2 {color: #808080; font-style: italic;} .sql.geshi_code .coMULTI {color: #808080; font-style: italic;} .sql.geshi_code .es0 {color: #000099; font-weight: bold;} .sql.geshi_code .br0 {color: #66cc66;} .sql.geshi_code .sy0 {color: #66cc66;} .sql.geshi_code .st0 {color: #ff0000;} .sql.geshi_code .nu0 {color: #cc66cc;} .sql.geshi_code span.xtra { display:block; }

CREATE TABLE `items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `price` float DEFAULT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=136 DEFAULT CHARSET=utf8 AUTO_INCREMENT=136 ;
 

и с характеристиками
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .sql.geshi_code {font-family:monospace;} .sql.geshi_code .imp {font-weight: bold; color: red;} .sql.geshi_code .kw1 {color: #993333; font-weight: bold;} .sql.geshi_code .co1 {color: #808080; font-style: italic;} .sql.geshi_code .co2 {color: #808080; font-style: italic;} .sql.geshi_code .coMULTI {color: #808080; font-style: italic;} .sql.geshi_code .es0 {color: #000099; font-weight: bold;} .sql.geshi_code .br0 {color: #66cc66;} .sql.geshi_code .sy0 {color: #66cc66;} .sql.geshi_code .st0 {color: #ff0000;} .sql.geshi_code .nu0 {color: #cc66cc;} .sql.geshi_code span.xtra { display:block; }

CREATE TABLE `extra_value` (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `item_id` int(11) NOT NULL DEFAULT '0',
  `value_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2531 DEFAULT CHARSET=utf8 AUTO_INCREMENT=2531 ;
 

У каждого товара есть несколько характеристик в таблице extra_value.
Необходимо вывести позиции соответсвующее нескольким характеристикам (т.е.
/** * GeSHi (C) 2004 - 2007 Nigel McNie, 2007 - 2008 Benny Baumann * (http://qbnz.com/highlighter/ and http://geshi.org/) */ .sql.geshi_code {font-family:monospace;} .sql.geshi_code .imp {font-weight: bold; color: red;} .sql.geshi_code .kw1 {color: #993333; font-weight: bold;} .sql.geshi_code .co1 {color: #808080; font-style: italic;} .sql.geshi_code .co2 {color: #808080; font-style: italic;} .sql.geshi_code .coMULTI {color: #808080; font-style: italic;} .sql.geshi_code .es0 {color: #000099; font-weight: bold;} .sql.geshi_code .br0 {color: #66cc66;} .sql.geshi_code .sy0 {color: #66cc66;} .sql.geshi_code .st0 {color: #ff0000;} .sql.geshi_code .nu0 {color: #cc66cc;} .sql.geshi_code span.xtra { display:block; }

WHERE extra_value.value_id IN (10, 11, 12)
 
).

1 ответов


Конкретно для вашего случая я бы предложил такой вариант. Тут для каждого итема отбирается три строки, в группировке по итемам считаем сколько различных value_id насобиралось (в данном случае больше 3-х быть не может). Полученный список нужных id-шников можно использовать для выборки из таблицы. Если их много, то конструкцию in лучше заменить на соединение join.
В любом случае недостатков море - двойное чтение таблицы итемов, группировка.


SELECT * FROM `items`
WHERE `id` in (
  SELECT `item_id`
  FROM `extra_value`
  WHERE `value_id` IN (10, 11, 12)
  GROUP BY `item_id`
  HAVING count(distinct `value_id`) = 3
);
 


SELECT `i`.* FROM `items` `i`
LEFT JOIN `extra_value` `ev` ON `i`.`id` = `ev`.`item_id`
WHERE `ev`.`value_id` IN (10, 11, 12)
GROUP BY `i`.`id`
 

Если надо выбрать items только те, у которых есть все три характеристики, то


 
  SELECT `i`.* ,
  MAX(CASE WHEN ev.value_id = 10 THEN 1 END) AS has_value_10,
  MAX(CASE WHEN ev.value_id = 11 THEN 1 END) AS has_value_11,
  MAX(CASE WHEN ev.value_id = 12 THEN 1 END) AS has_value_12
  FROM `items` `i`  
  INNER JOIN `extra_value` `ev` ON `i`.`id` = `ev`.`item_id`
     AND `ev`.`value_id` IN (10, 11, 12)
  GROUP BY `i`.`id`
  HAVING has_value_10 IS NOT NULL
     AND has_value_11 IS NOT NULL  AND has_value_12 IS NOT NULL
 

Если же надо показывать все items, то меняем INNER JOIN на LEFT JOIN и убираем HAVING