Отношение «многие ко многим» SQL: как получить все связанные записи в одном запросе? - PullRequest
0 голосов
/ 15 июля 2010

У меня те же таблицы, что и в этом вопросе: MySql-запрос по отношению ко многим-ко-многим . Однако я борюсь с тем, как построить запрос, который бы получил растение со всеми его атрибутами. То есть если я хочу P1, я получаю

P1 | A1 | A2 | A3 or P1 | A1, A2, A3

В отличие от

P1 | A1
P1 | A2
P1 | A3

если я хочу все растения, я получаю

P1 | A1 | A2 | A3          P1 | A1, A2, A3
P2 | A1 | A2         or    P2 | A1, A2
P3 | A2 | A3               P3 | A2, A3

И наоборот, то есть отображать все растения для данного параметра. Прежде всего - возможно ли создать такой SQL-запрос?

В настоящий момент я получаю каждое растение один раз, и для каждой строки я снова получаю доступ к базе данных, запрашивая атрибуты. Как вы, наверное, понимаете, это очень неэффективно, поэтому я надеюсь, что вы можете указать мне правильное направление.

РЕДАКТИРОВАТЬ: Я хотел бы получить одно растение на одну строку и все атрибуты в той же строке.

Ответы [ 5 ]

3 голосов
/ 15 июля 2010

Вы имеете в виду что-то вроде следующего?Я немного упростил вещи, удалив таблицу ссылок, но идея та же:

SELECT
  plant.name,
  GROUP_CONCAT(attrib.name) AS attribs
FROM plant
JOIN attrib ON attrib.plant_id = plant.id
GROUP BY plant.id;

+------+----------------+
| name | attribs        |
+------+----------------+
| P1   | A1-1,A1-2,A1-3 |
| P2   | A2-1,A2-2,A2-3 |
| P3   | A3-1,A3-2,A3-3 |
+------+----------------+

Или вот это:

SELECT plant.name, GROUP_CONCAT(attrib.name)
FROM plant JOIN attrib
ON attrib.plant_id = plant.id
WHERE attrib.name IN ('A2-1', 'A2-3', 'A3-2')
GROUP BY plant.id;

+------+---------------------------+
| name | GROUP_CONCAT(attrib.name) |
+------+---------------------------+
| P2   | A2-1,A2-3                 |
| P3   | A3-2                      |
+------+---------------------------+

Вышеприведенное взято из следующих вставок:

INSERT INTO plant (name) VALUES
  ('P1'), ('P2'), ('P3');

INSERT INTO attrib (plant_id, name) VALUES
  (1, 'A1-1'), (1, 'A1-2'), (1, 'A1-3'),
  (2, 'A2-1'), (2, 'A2-2'), (2, 'A2-3'),
  (3, 'A3-1'), (3, 'A3-2'), (3, 'A3-3');
1 голос
/ 15 июля 2010

Вы пометили этот PHP, поэтому давайте используем PHP для решения проблемы.Где $db - соединение PDO , а структура таблицы определена в комментарии knittl :

$plant_id = 1;
$plant_attributes = array();
$query = "knittl's query from above, because it works well enough for us.";
$sth = $db->prepare($query);
$sth->execute($plant_id);
while($row = $sth->fetch(PDO::FETCH_ASSOC))
    $plant_attributes[] = $row['attrid'];

Tada!Теперь у вас есть список всех атрибутов для выбранного растения.Для всех растений:

$plant_attributes = array();
$query = "knittl's query from above, minus the WHERE clause";
$sth = $db->prepare($query);
$sth->execute();
while($row = $sth->fetch(PDO::FETCH_ASSOC))
    $plant_attributes[ $row['plantid'] ][] = $row['attrid'];

Тада!Теперь у вас есть список всех растений и их атрибутов.

То, о чем вы изначально просили, похоже на « сводную таблицу » или « crosstab ».MySQL не может делать то, что вы просили изначально.Может быть возможно создать хранимую процедуру, которая пытается вернуть данные в табличном формате, а не в виде столбца, как это существует в базе данных, но это невероятная боль.С другой стороны, это не невероятная боль.

0 голосов
/ 16 июля 2010

Этот запрос вернет все растения вместе с их атрибутами. Таблицы как в этом вопросе Запрос MySql по отношению ко многим ко многим .

SELECT `Plant`.`name`,
GROUP_CONCAT(`Attribute`.`name`) AS attribs
FROM `plant`, `attribute`, `hasAttribute`
WHERE `Plant`.`pid` = `hasAttribute`.`pid`
AND `Attribute`.`aid` = `hasAttribute`.`aid`
GROUP BY `Plant`.`name`

Должен вернуться:

+------+----------+
| name | attribs  |
+------+----------+
| P1   | A1,A2,A3 |
| P2   | A1,A2    |
| P3   | A2,A3    |
+------+----------+
0 голосов
/ 15 июля 2010

Я думаю, что вы должны использовать процедуру базы данных вместо запроса, но я не знаю процедур mysql, так что я не могу помочь вам с этим. Но я надеюсь, что это даст вам новое направление мышления и, возможно, вы найдете решение :)

0 голосов
/ 15 июля 2010

просто присоединитесь к ним:

    select p.*, a.*
      from plants p
inner join plantattributes pa
        on p.plantid = pa.plantid
inner join attributes a
        on pa.attrid = a.attrid
     where pa.plantid = ?

, если вы хотите, чтобы все растения для данного атрибута использовали where a.attrid = ? вместо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...