выбрать элементы, которые имеют несколько совпадений в нормализованной таблице - PullRequest
2 голосов
/ 21 апреля 2011

У меня есть таблица, в которой хранится куча объектов.Каждый объект может иметь много цветов, которые хранятся в нормализованной таблице, связанной с object_id.

Если я пойду

SELECT `object_name` FROM `objects`
  LEFT JOIN `object_color` USING `object_id`
    WHERE `object_color` IN ('red', 'blue');

Тогда я получу объекты, которые «красные» ИЛИ «синий».Мне нужно получить все объекты, которые «красные» И «синие».Если я пойду:

SELECT `object_name` FROM `objects`
  LEFT JOIN `object_color` USING `object_id`
    WHERE `object_color` = 'red' AND `object_color` = 'blue';

Тогда я ничего не получу, так как в каждой строке есть только один object_color, и он не может быть и тем и другим.Кроме того, на самом деле, цвета идентификаторы с именами в другой таблице.Я здесь все упростил ради вопроса.

Мне нужно иметь возможность искать неограниченное количество цветов.

Спасибо

РЕДАКТИРОВАТЬ:

object_color находится только в таблице object_color.

И любой объект будет иметь один единственный цвет.

Ответы [ 4 ]

4 голосов
/ 21 апреля 2011
Select object_name
From objects
Where object_color In('red','blue')
Group By object_name
Having Count(Distinct object_color) = 2

Кстати, вы никогда не упоминаете, из какой таблицы происходит столбец object_color.Если это из таблицы object_color:

Select O.object_name
From objects As O
    Join object_color As C
        On C.object_id = O.object_id
Where C.object_color In('red','blue')
Group By O.object_name
Having Count(Distinct C.object_color) = 2

В приведенном выше запросе предполагается, что данная строка object может не иметь несколько строк object_color одного цвета.Однако, как заметил Джоэл С., если бы у object было несколько object_color строк красного или синего цвета, это потребовало бы другого запроса.:

Select ...
From objects As O
Where O.object_id In    (
                        Select C1.object_id
                        From object_color As C1
                        Where C1.object_color = 'red'
                        )
    And O.object_id In  (
                        Select C1.object_id
                        From object_color As C1
                        Where C1.object_color = 'blue'
                        )

Еще одно решение:

Select O.object_name
From objects As O
    Join    (
            Select C1.object_id, C1.object_color
            From object_color As C1
            Where C1.color In('red','blue')
            Group By C1.object_id, C1.object_color
            ) As Z
        On Z.object_id = O.object_id
Group By O.object_name
Having Count(*) = 2
2 голосов
/ 21 апреля 2011

Я предпочитаю ON, а не USING:

SELECT o.object_name
FROM objects o
  JOIN object_color oc
    ON o.object_id = oc.object_id
WHERE oc.object_color IN ( 'red', 'blue' )
GROUP BY o.object_id
HAVING COUNT(o.object_id) = ( SELECT COUNT(*)
                              FROM ( 'red', 'blue' )
                            )

Предполагая, что объект не может иметь много строк одного цвета.

1 голос
/ 21 апреля 2011

Вам понадобится многократное объединение

SELECT `object_name` FROM `objects`
  LEFT JOIN `object_color` USING `object_id`
    WHERE `object_color` = 'red'
  LEFT JOIN `object_color` USING `object_id`
    WHERE `object_color` = 'blue' ;
0 голосов
/ 21 апреля 2011

Вы также можете использовать INTERSECT, если он поддерживается в используемом SQL.

SELECT object_name
FROM objects o, objects_color oc
WHERE object_color = 'red'
and o.object_id = oc.object_id

INTERSECT

SELECT object_name
FROM objects o, objects_color oc
WHERE object_color = 'blue'
and o.object_id = oc.object_id

Это будет пересекать две таблицы и показывать только те строки, у которых красный и синий цвета совпадают с одинаковымиимя объекта.

...