SQL - уникальный выбор (возможно, отсутствие) дочерних элементов в иерархии - PullRequest
1 голос
/ 16 января 2012

У меня есть простая иерархия component в MySQL, которая описывается таблицей assembly.

SELECT * FROM component;

+----+--------+------+
¦ id ¦ name   ¦ type ¦
+----+--------+------+
¦ 11 ¦ car1   ¦ A    ¦
¦ 12 ¦ car2   ¦ A    ¦
¦ 13 ¦ car3   ¦ A    ¦
¦ 21 ¦ motor1 ¦ B    ¦
¦ 22 ¦ motor2 ¦ B    ¦
¦ 31 ¦ brake1 ¦ C    ¦
+----+--------+------+

SELECT * FROM assembly;

+----+-----------+----------+
¦ id ¦ parent_id ¦ child_id ¦
+----+-----------+----------+
¦  1 ¦        11 ¦       21 ¦
¦  2 ¦        12 ¦       22 ¦
¦  3 ¦        11 ¦       31 ¦
¦  4 ¦        13 ¦       31 ¦
+----+-----------+----------+

РЕДАКТИРОВАТЬ: Как правильно догадался Демс, третья запись (id = 3) отсутствовала в исходном сообщении. Таблица теперь заполнена.

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

Желаемый вывод:

+----------+------------+
¦ car_name ¦ motor_name ¦
+----------+------------+
¦     car1 ¦     motor1 ¦
¦     car2 ¦     motor2 ¦
¦     car3 ¦            ¦
+----------+------------+

Есть ли простой способ получить это?

У автомобиля не более одного моторного ребенка.

Внешнее соединение с видом на компоненты двигателя дает две строки для car1, и этого не должно быть:

CREATE VIEW comp_motor
AS 
SELECT * FROM component
WHERE type='B';

SELECT parent.name, child.name
FROM component parent
LEFT JOIN assembly a ON parent.id = a.parent.id
LEFT JOIN comp_motor child ON a.child_id = child.id
WHERE 
parent.type = 'A';

Это дает

+------+--------+
¦ name ¦   name ¦
+------+--------+
¦ car1 ¦ motor1 ¦
¦ car1 ¦ NULL   ¦
¦ car2 ¦ motor2 ¦
¦ car3 ¦ NULL   ¦ 
+------+--------+

Второй ряд не должен быть там. Конечно, DISTINCT не поможет в этом случае.

Я не могу изменить структуру базы данных.

Любой ввод будет приветствоваться!

Ответы [ 2 ]

2 голосов
/ 16 января 2012

Не могли бы вы выполнить следующую инструкцию SELECT и рассказать нам, что вы получаете?

SELECT * FROM component WHERE type = 'A'

Я думаю, что у вас есть Car1 там дважды ...

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

О, или у вас есть две записи для Car1 в сборочной таблице?Что это показывает?

SELECT * FROM assembly WHERE parent_id = 11

Если это источник, попробуйте это ...

SELECT
  parent.name,
  child.name
FROM
  component parent
LEFT JOIN
  (
    assembly a 
  INNER JOIN
    comp_motor child
      ON a.child_id = child.id
  )
    ON parent.id = a.parent.id
WHERE 
  parent.type = 'A';
0 голосов
/ 16 января 2012

Попробуйте:

select car.name car_name, coalesce(motor.name, 'No motor') motor_name
from component car
left join (select a.parent_id, c.name
           from assembly a
           inner join component c 
                   on a.child_id = c.id and c.type = 'B') motor
       on car.id = motor.parent_id
where car.type = 'A'
...