2013-09-25 2 views
0

У меня есть БД MySQL, которая должна предоставлять атрибуты, связанные с таксономией. Я хочу иметь список всех атрибутов, включая «унаследованные атрибуты» для данного элемента в таксономии. Я не эксперт SQL & многому научился (и плагиат) с этого сайта. Одна вещь, которую я узнал здесь, - это использовать таблицу закрытия для представления моей Иерархии. То, что мне нужно сделать для моей базы данных, - связать большое количество атрибутов с элементами внутри иерархии. Однако я не могу понять, как захватить все атрибуты, связанные с данным узлом и всеми его родителями. Я создал следующую примерную базу данных для этого вопроса (не стесняйтесь комментировать что-либо об этой схеме, поддельные данные - это просто шум).Список всех атрибутов из каждого элемента в таксономии в MySQL

Моей пример структура базы данных MySQL выглядит следующим образом:

-- Simple Sample 
    SET FOREIGN_KEY_CHECKS=0; 
    DROP TRIGGER IF EXISTS inheritance_tree_insert; 
    DROP TRIGGER IF EXISTS inheritance_tree_update; 
    DROP TABLE IF EXISTS inheritance_paths; 
    DROP TABLE IF EXISTS inheritance_tree; 
    DROP TABLE IF EXISTS attributes; 
    SET FOREIGN_KEY_CHECKS=1; 


    CREATE TABLE `inheritance_tree` (
     `it_id`  INT NOT NULL,   -- PK 
     `parent`  INT,     -- Parent id & FK 
     `child_order` INT,     -- Oder of siblings 
     `name`  VARCHAR(500) NOT NULL, -- Name for the entry 
     PRIMARY KEY (`it_id`), 
     FOREIGN KEY (`parent`) REFERENCES inheritance_tree(`it_id`) ON DELETE CASCADE, 
     INDEX(`name`) 
    ) ENGINE = INNODB; 

    -- Trigger to update the paths table for new entries 
    DELIMITER // 

    CREATE TRIGGER `inheritance_tree_insert` AFTER INSERT ON `inheritance_tree` FOR EACH ROW 
    BEGIN 
     INSERT INTO `inheritance_paths` (`ancestor`, `descendant`, `len`) 
      SELECT `ancestor`, NEW.`it_id`, len + 1 FROM `inheritance_paths` 
       WHERE `descendant` = NEW.`parent` 
       UNION ALL SELECT NEW.`it_id`, NEW.`it_id`, 0; 
    END; // 
    DELIMITER ; 


    DELIMITER // 
    CREATE TRIGGER `inheritance_tree_update` BEFORE UPDATE ON `inheritance_tree` FOR EACH ROW 
    BEGIN 
     -- From http://www.mysqlperformanceblog.com/2011/02/14/moving-subtrees-in-closure-table/ 
     IF OLD.`parent` != NEW.`parent` THEN 
      -- Remove the node from its current parent 
      DELETE a FROM `inheritance_paths` AS a 
      JOIN `inheritance_paths` AS d ON a.`descendant` = d.`descendant` 
      LEFT JOIN `inheritance_paths` AS x 
      ON x.`ancestor` = d.`ancestor` AND x.`descendant` = a.`ancestor` 
      WHERE d.`ancestor` = OLD.`it_id` AND x.`ancestor` IS NULL; 

      -- Add the node to its new parent 
      INSERT `inheritance_paths` (`ancestor`, `descendant`, `len`) 
      SELECT supertree.`ancestor`, subtree.`descendant`, supertree.`len`+subtree.`len`+1 
      FROM `inheritance_paths` AS supertree JOIN `inheritance_paths` AS subtree 
      WHERE subtree.`ancestor` = OLD.`it_id` 
      AND supertree.`descendant` = NEW.`parent`; 
     END IF; 
    END; // 
    DELIMITER ; 


    CREATE TABLE `inheritance_paths` (
     `ancestor`  INT NOT NULL, 
     `descendant` INT NOT NULL, 
     `len`   INT NOT NULL, 
     PRIMARY KEY (`ancestor`, `descendant`), 
     FOREIGN KEY (`ancestor`) REFERENCES inheritance_tree(`it_id`) ON DELETE CASCADE, 
     FOREIGN KEY (`descendant`) REFERENCES inheritance_tree(`it_id`) ON DELETE CASCADE 
    ) ENGINE = INNODB; 

    INSERT INTO `inheritance_tree` VALUES(1, NULL, NULL, 'Animal'); 
    INSERT INTO `inheritance_tree` VALUES(2, 1, 1, 'Mammal'); 
    INSERT INTO `inheritance_tree` VALUES(3, 1, 2, 'Bird'); 
    INSERT INTO `inheritance_tree` VALUES(4, 1, 3, 'Reptile'); 
    INSERT INTO `inheritance_tree` VALUES(5, 2, 2, 'Feline'); 
    INSERT INTO `inheritance_tree` VALUES(6, 2, 1, 'Bovine'); 
    INSERT INTO `inheritance_tree` VALUES(7, 1, 3, 'Fish'); 
    INSERT INTO `inheritance_tree` VALUES(8, 4, 1, 'Snake'); 
    INSERT INTO `inheritance_tree` VALUES(9, 4, 2, 'Lizard'); 
    INSERT INTO `inheritance_tree` VALUES(10, NULL, NULL, 'Machine'); 
    INSERT INTO `inheritance_tree` VALUES(11, 10, 1, 'Automobile'); 
    INSERT INTO `inheritance_tree` VALUES(12, 10, 2, 'OfficeMachine'); 
    INSERT INTO `inheritance_tree` VALUES(13, 10, 3, 'Robot'); 

    DELIMITER ; 

    CREATE TABLE `attributes` (
     `a_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'the unique identifier', 
     `attribute_name` varchar(255) DEFAULT NULL, 
     `attribute_type` int(11) NOT NULL, 
     PRIMARY KEY (`a_id`), 
     KEY `fk_attributes_attribute_type1_idx` (`attribute_type`), 
     CONSTRAINT `fk_attributes_attribute_type1_idx` FOREIGN KEY (`attribute_type`) REFERENCES `inheritance_tree` (`it_id`) ON DELETE NO ACTION ON UPDATE NO ACTION 
    ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1; 

    INSERT INTO `attributes` VALUES(1, 'IsAlive', 1);     -- Animal 
    INSERT INTO `attributes` VALUES(2, 'HasMaximumLifeSpan', 1);  -- Animal 
    INSERT INTO `attributes` VALUES(3, 'IsNotAlive', 10);    -- Machine 
    INSERT INTO `attributes` VALUES(4, 'HasIndeterminantLifeSpan', 10); -- Machine 
    INSERT INTO `attributes` VALUES(5, 'BreathesAir', 2);    -- Mammal 
    INSERT INTO `attributes` VALUES(6, 'CanFly', 3);     -- Bird 
    INSERT INTO `attributes` VALUES(7, 'HasFeathers', 3);    -- Bird 
    INSERT INTO `attributes` VALUES(8, 'ColdBlooded', 4);    -- Reptile 
    INSERT INTO `attributes` VALUES(9, 'HasFourLegs', 5);    -- Feline 
    INSERT INTO `attributes` VALUES(10, 'HasFourLegs', 6);    -- Bovine 
    INSERT INTO `attributes` VALUES(11, 'ColdBlooded', 7);    -- Fish 
    INSERT INTO `attributes` VALUES(12, 'HasNoLegs', 8);    -- Snake 
    INSERT INTO `attributes` VALUES(13, 'HasFourLegs', 9);    -- Lizard 
    INSERT INTO `attributes` VALUES(14, 'ConsumesGasoline', 11);  -- Automobile 
    INSERT INTO `attributes` VALUES(15, 'ConsumesElectricity', 12);  -- OfficeMachine 
    INSERT INTO `attributes` VALUES(16, 'ConsumesElectricity', 13);  -- Robot 
    INSERT INTO `attributes` VALUES(17, 'WarmBlooded', 2);    -- Mammal 
    INSERT INTO `attributes` VALUES(18, 'WarmBlooded', 3);    -- Bird 
    INSERT INTO `attributes` VALUES(19, 'BreathesWater', 7);   -- Fish 
    INSERT INTO `attributes` VALUES(20, 'HasScales', 8);    -- Snake 
    INSERT INTO `attributes` VALUES(21, 'HasSkin', 9);     -- Lizard 

Предположение:

1.Вс сущности в систематике имеют уникальные имена. Это означает, что в любом из деревьев таксономии есть один и только один подтип, называемый «Рыба».

2.Attributes не являются уникальными и могут повторить

ЦЕЛЬ:

Учитывая тип входа «Ящерица» Я хотел бы один запрос, который возвращает следующий список записей атрибутов:

1 , IsAlive, 1

2, HasMaximumLifeSpan, 1

5, BreathesAir, 2

8, холоднокровных, 4

13, HasFourLegs, 9

21, HasSkin, 9

+0

Как вы связываете атрибут a_id с атрибутом inheritence_tree? Я бы предположил, что вам понадобится какая-то ассоциация, чтобы вы могли каскадировать атрибуты. Возможно, это самая проблема, которую вы пытаетесь решить. Если это так, используйте таблицу атрибутов в качестве таблицы «look_up», из которой вы привязываете запись inhertience_tree, поэтому вы должны добавить дополнительный столбец или иметь таблицу inheritence_tree_attribute для создания ассоциации. Имеет смысл? –

+0

Поле таблицы атрибутов 'attribute_type' указывает на один узел в иерархии (таблица inheritance_tree). –

+0

Ниже приведен пример извлечения атрибутов только для Lizard (без унаследованных атрибутов): SELECT * FROM атрибуты WHERE attribute_type IN (SELECT it_id FROM inheritance_tree WHERE name LIKE 'Lizard') Это приводит к возврату 2 записей: 13, HasFourLegs, 9 21, HasSkin, 9 –

ответ

0
SELECT a.* 
FROM inheritance_tree t 
    JOIN inheritance_paths p ON p.descendant  = t.it_id 
    JOIN attributes  a ON a.attribute_type = p.ancestor 
WHERE t.name = 'Lizard' 

Посмотреть по sqlfiddle.

Обратите внимание, что ваш пример вывода включает a_id = 5 (BreathesAir), который является свойством it_id = 2 (Млекопитающее), которого нет в родословной Ящерицы.

+0

Эй, как вы «sqlfiddleise» DDL? Я попытался запустить скрипт, но он продолжал сбой ... –

+0

@RobertoNavarro: sqlfiddle не распознает команду DELIMITER (которая является клиентской инструкцией); необходимо изменить разделитель инструкций, используя настройку под полем ввода, а затем использовать этот разделитель. – eggyal

+0

Удивительный! И это так просто (по сравнению с запутанным SQL, который я писал). Мне нужно изучить инструкцию JOIN, чтобы я мог понять, что здесь происходит. Извините за неправильное «BreathesAir» ... Я сделал это вручную немного слишком quiclky. Благодаря! –

Смежные вопросы