how to get data from relational tables (many to many) - mysql

I have these three main tables Microdisenos, competencias and resultados.
My problem is this: I want to know what are the resultados that belong to the competencias of a microdisenos.
I know how to do it when relationships are one to many, but in this case it is many to many and I do not know how to handle those intermediate tables.
Thanks for your help.

The only way is to join throught all the columns:
SELECT * (or whatever you need)
FROM resultados r
INNER JOIN competencia_resultado cr
ON r.id = cr.resultado_id
INNER JOIN cometencias c
ON c.id = cr.cometencia_id
INNER JOIN competencia_microdisendo cm
ON c.id = cm.competencia_id
INNER JOIN microdisendos m
ON m.id = cm.microdisendo_id
And if you want to select just the once that belong to one specific microdesendo add the WHERE clause with m.id

CREATE DATABASE testDB;
USE testDB;
CREATE TABLE microdisenos (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
description VARCHAR(255),
PRIMARY KEY (id)
);
CREATE TABLE competencias (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
modulo VARCHAR(128),
PRIMARY KEY (id)
);
CREATE TABLE competencia_microdiseno (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
microdiseno_id INTEGER UNSIGNED,
competencia_id INTEGER UNSIGNED,
PRIMARY KEY (id),
FOREIGN KEY (microdiseno_id) REFERENCES microdisenos (id),
FOREIGN KEY (competencia_id) REFERENCES competencias (id)
);
CREATE TABLE resultados (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
description VARCHAR(256),
PRIMARY KEY (id)
);
CREATE TABLE competencia_resultado(
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
resultado_id INTEGER UNSIGNED,
competencia_id INTEGER UNSIGNED,
PRIMARY KEY (id),
FOREIGN KEY (resultado_id) REFERENCES resultados (id),
FOREIGN KEY (competencia_id) REFERENCES competencias (id)
);
INSERT INTO competencias VALUES (0, 'Compentencia AA');
INSERT INTO competencias VALUES (0, 'Compentencia BB');
INSERT INTO competencias VALUES (0, 'Compentencia CC');
INSERT INTO competencias VALUES (0, 'Compentencia DD');
INSERT INTO competencias VALUES (0, 'Compentencia EE');
INSERT INTO microdisenos VALUES (0, 'Microdisenos 101');
INSERT INTO microdisenos VALUES (0, 'Microdisenos 202');
INSERT INTO microdisenos VALUES (0, 'Microdisenos 303');
INSERT INTO microdisenos VALUES (0, 'Microdisenos 404');
INSERT INTO microdisenos VALUES (0, 'Microdisenos 505');
INSERT INTO resultados VALUES (0, 'Resultados 11');
INSERT INTO resultados VALUES (0, 'Resultados 22');
INSERT INTO resultados VALUES (0, 'Resultados 33');
INSERT INTO resultados VALUES (0, 'Resultados 44');
INSERT INTO resultados VALUES (0, 'Resultados 55');
INSERT INTO competencia_microdiseno VALUES(0, 1, 1);
INSERT INTO competencia_microdiseno VALUES(0, 1, 2);
INSERT INTO competencia_microdiseno VALUES(0, 1, 3);
INSERT INTO competencia_microdiseno VALUES(0, 2, 4);
INSERT INTO competencia_microdiseno VALUES(0, 2, 5);
INSERT INTO competencia_microdiseno VALUES(0, 3, 1);
INSERT INTO competencia_microdiseno VALUES(0, 3, 2);
INSERT INTO competencia_microdiseno VALUES(0, 4, 3);
INSERT INTO competencia_microdiseno VALUES(0, 4, 4);
INSERT INTO competencia_microdiseno VALUES(0, 4, 5);
INSERT INTO competencia_microdiseno VALUES(0, 5, 1);
INSERT INTO competencia_microdiseno VALUES(0, 5, 2);
INSERT INTO competencia_microdiseno VALUES(0, 5, 3);
INSERT INTO competencia_resultado VALUES(0, 1, 1);
INSERT INTO competencia_resultado VALUES(0, 2, 2);
INSERT INTO competencia_resultado VALUES(0, 3, 3);
INSERT INTO competencia_resultado VALUES(0, 4, 4);
INSERT INTO competencia_resultado VALUES(0, 5, 5);
INSERT INTO competencia_resultado VALUES(0, 1, 1);
INSERT INTO competencia_resultado VALUES(0, 2, 2);
INSERT INTO competencia_resultado VALUES(0, 3, 3);
INSERT INTO competencia_resultado VALUES(0, 4, 4);
INSERT INTO competencia_resultado VALUES(0, 5, 5);
INSERT INTO competencia_resultado VALUES(0, 1, 1);
INSERT INTO competencia_resultado VALUES(0, 2, 2);
INSERT INTO competencia_resultado VALUES(0, 3, 3);
-- Give me all (unique) Resultados for Compentencias for given Microdisenos
SELECT DISTINCT r.*
FROM resultados r, competencia_resultado cr, competencias c, competencia_microdiseno cm, microdisenos m
WHERE r.id = cr.resultado_id
AND c.id = cr.competencia_id
AND c.id = cm.competencia_id
AND m.id = cm.microdiseno_id
AND m.description = "Microdisenos 303";
The result would be:
# id, description
---- ---------------
1, Resultados 11
2, Resultados 22
Option 2:
Subquery
SELECT DISTINCT r.*
FROM resultados r
WHERE r.id IN ( SELECT DISTINCT cr.id
FROM competencia_resultado cr
WHERE cr.competencia_id IN (
SELECT DISTINCT c.id
FROM competencias c
WHERE c.id IN (
SELECT DISTINCT cm.competencia_id
FROM competencia_microdiseno cm, microdisenos m
WHERE m.id = cm.microdiseno_id
AND m.description = "Microdisenos 303" )
)
);

Related

SQL Query to find number of users in a Job Area

I have three tables:
jobAreas (id, title)
jobSkills (id,title, jobAreaID)
userSkills (id, userID, jobSkillID)
Each jobSkills entry belongs to a JobArea (linked by foreign key jobAreaID). And each userSkills entry has a JobSkill that is related to a jobSkill.
I am trying to create a SQL select query that will list the number of users that belong to each Job Area.
SELECT ja.id, ja.title, COUNT(*) as numUsers FROM user_skill_types uskills INNER JOIN job_areas ja INNER JOIN skill_types st ON ja.id = st.parent_id GROUP BY ja.id
But the numbers I am getting are not correct.
Given the following example (based on the table structure provided in the question).
CREATE TABLE `jobareas` (
`id` int(11) NOT NULL,
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `jobareas` (`id`, `title`) VALUES
(1, 'area1'),
(2, 'area2'),
(3, 'area3'),
(4, 'area4'),
(5, 'area5'),
(6, 'area6'),
(7, 'area7'),
(8, 'area8');
-- --------------------------------------------------------
CREATE TABLE `jobskills` (
`id` int(11) NOT NULL,
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`jobAreaID` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `jobskills` (`id`, `title`, `jobAreaID`) VALUES
(1, 'skill1', 1),
(2, 'skill2', 3),
(3, 'skill3', 3),
(4, 'skill4', 7),
(5, 'skill5', 4),
(6, 'skill6', 5),
(7, 'skill7', 1),
(8, 'skill8', 7),
(9, 'skill9', 6),
(10, 'skill10', 3),
(11, 'skill11', 4),
(12, 'skill12', 2),
(13, 'skill13', 6),
(14, 'skill14', 7),
(15, 'skill15', 2);
-- --------------------------------------------------------
CREATE TABLE `userskills` (
`id` int(11) NOT NULL,
`userID` int(11) NOT NULL,
`jobSkillID` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `userskills` (`id`, `userID`, `jobSkillID`) VALUES
(1, 5, 10),
(2, 2, 11),
(3, 4, 14),
(4, 4, 6),
(5, 2, 8),
(6, 6, 9),
(7, 3, 9),
(8, 1, 12),
(9, 1, 3),
(10, 5, 10);
ALTER TABLE `jobareas`
ADD UNIQUE KEY `id` (`id`);
ALTER TABLE `jobskills`
ADD PRIMARY KEY (`id`),
ADD KEY `jobAreaID` (`jobAreaID`);
ALTER TABLE `userskills`
ADD PRIMARY KEY (`id`),
ADD KEY `userID` (`userID`),
ADD KEY `jobSkillID` (`jobSkillID`);
ALTER TABLE `jobskills`
ADD CONSTRAINT `jobskills_ibfk_1` FOREIGN KEY (`jobAreaID`) REFERENCES `jobareas` (`id`);
ALTER TABLE `userskills`
ADD CONSTRAINT `userskills_ibfk_1` FOREIGN KEY (`jobSkillID`) REFERENCES `jobskills` (`id`);
Your query should use DISTINCT.
SELECT COUNT(DISTINCT(`us`.`userID`)) AS `num`,`ja`.`title` FROM `userskills` `us`
INNER JOIN `jobskills` `js` ON `js`.`id` = `us`.`jobSkillID`
INNER JOIN `jobareas` `ja` ON `ja`.`id` = `js`.`jobAreaID`
GROUP BY `ja`.`id`;
The results can be checked in this SQLFiddle
Your SQL Query shared does not seem to match the schema shared. Also you have not specified how to join the job_areas table
Use
select
ja.id, ja.title , count(us.id) as numUsers
from jobAreas ja
INNER JOIN jobSkills js on ja.id = js.jobAreaID
INNER JOIN userSkills us on js.id = us.jobSkillID
GROUP BY ja.id, ja.title
You are probably getting duplicates in your result because of users having multiple skills or jobs having multiple areas, or both. Rather than COUNT(*), use COUNT(DISTINCT userID) to work around that:
SELECT ja.id, ja.title, COUNT(DISTINCT us.userID) as numUsers
FROM jobAreas ja
JOIN jobSkills js ON js.jobAreaID = ja.id
JOIN userSkills us ON us.jobSkillsID = js.id
GROUP BY ja.id, ja.title
Note I've written the query based on the schema in your question. Based on the query you have written, it should probably look something like (it's not clear what the user_skill_types userID column is called, or how to JOIN user_skill_types to job_skills):
SELECT ja.id, ja.title, COUNT(DISTINCT uskills.userID) as numUsers
FROM job_areas ja
JOIN skill_types st ON ja.id = st.parent_id
JOIN user_skill_types uskills ON uskills.jobSkillID = st.id
GROUP BY ja.id, ja.title

In on result, get a number of dependency

I have this MySQL DB :
MySQL in order to create DB + set of test value :
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
CREATE TABLE table_status ( Id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, Status CHAR(27) NOT NULL) ENGINE=INNODB;
INSERT INTO table_status (Id, Status) VALUES (1, 'CREATED'), (2, 'UNSURE'), (3, 'RUNNING'), (4, 'BEGIN_ACTION_TRUE'), (5, 'STOPPED_ACTION_TRUE_OK'), (6, 'STOPPED_ACTION_TRUE_NOT_OK'), (7, 'BEGIN_ACTION_FALSE'), (8, 'STOPPED_ACTION_FALSE_OK'), (9, 'STOPPED_ACTION_FALSE_NOT_OK'), (10, 'STOPPED_NOT_OK'), (11, 'STOPPED_OK'), (12, 'CANCEL_REQUESTED'), (13, 'CANCELLED');
CREATE TABLE table_group ( Id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, Status TINYINT UNSIGNED NOT NULL DEFAULT 1, CONSTRAINT fk_group_Status FOREIGN KEY (Status) REFERENCES table_status(Id)) ENGINE=INNODB;
CREATE TABLE table_task ( Id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, IdGroup BIGINT UNSIGNED NOT NULL, Status TINYINT UNSIGNED NOT NULL DEFAULT 1, Command TEXT NOT NULL, CONSTRAINT fk_task_IdGroup FOREIGN KEY (IdGroup) REFERENCES table_group(Id) ON DELETE CASCADE, CONSTRAINT fk_task_Status FOREIGN KEY (Status) REFERENCES table_status(Id)) ENGINE=INNODB;
CREATE TABLE table_dependency ( IdBeforeTask BIGINT UNSIGNED NOT NULL, IdAfterTask BIGINT UNSIGNED NOT NULL, PRIMARY KEY (IdBeforeTask, IdAfterTask), CONSTRAINT fk_dependency_IdBeforeTask FOREIGN KEY (IdBeforeTask) REFERENCES table_task(Id) ON DELETE CASCADE, CONSTRAINT fk_dependency_IdAfterTask FOREIGN KEY (IdAfterTask) REFERENCES table_task(Id) ON DELETE CASCADE) ENGINE=INNODB;
INSERT INTO table_group (Id) VALUES (1), (2), (3), (4);
INSERT INTO table_task (IdGroup, Command) VALUES (1, "command_group_1_task_1"), (1, "command_group_1_task_2"), (1, "command_group_1_task_3"), (2, "command_group_2_task_1"), (2, "command_group_2_task_2"), (2, "command_group_2_task_3"), (3, "command_group_3_task_1"), (3, "command_group_3_task_2"), (3, "command_group_3_task_3"), (4, "command_group_4_task_1"), (4, "command_group_4_task_2"), (4, "command_group_4_task_3");
INSERT INTO table_dependency (IdBeforeTask, IdAfterTask) VALUES (1, 2), (2, 3), (4, 5), (5, 6), (7, 8), (8, 9), (10, 11), (11, 12);
The data in table_status is fixed to this :
INSERT INTO table_status (Id, Status) VALUES
(1, 'CREATED')
(2, 'UNSURE')
(3, 'RUNNING')
(4, 'BEGIN_ACTION_TRUE')
(5, 'STOPPED_ACTION_TRUE_OK')
(6, 'STOPPED_ACTION_TRUE_NOT_OK')
(7, 'BEGIN_ACTION_FALSE')
(8, 'STOPPED_ACTION_FALSE_OK')
(9, 'STOPPED_ACTION_FALSE_NOT_OK')
(10, 'STOPPED_NOT_OK')
(11, 'STOPPED_OK')
(12, 'CANCEL_REQUESTED')
(13, 'CANCELLED')
The purpose is to have a group containing task, each task can be dependant on another one.
What I want to obtain :
Group.Id, NB_TASK_TOTAL, NB_TASK_CREATED, NB_TASK_UNSURE
But there is a trap : The number of NB_TASK_CREATED is defined as : the number of task with status to CREATED and with no unresolved dependency.
An unresolved dependency is defined as a task depend on another wich have a Status != 11 (STOPPED_OK).
So if I have this :
table_dependency :
IdBeforeTask IdAfterTask
1 2
2 3
table_task :
Id IdGroup Status Command
1 1 1 command_1
2 1 1 command_2
3 1 1 command_3
I want to have
Group.Id, NB_TASK_TOTAL, NB_TASK_CREATED, NB_TASK_UNSURE
1 3 1 0
Here my unsucesful try :
SELECT
G.Id,
(SELECT COUNT(T.Id) FROM table_task as T WHERE T.IdGroup = G.Id),
(SELECT COUNT(T.Status = 1) FROM table_task as T WHERE T.IdGroup = G.Id AND T.Id NOT IN (SELECT IdAfterTask from table_dependency as D1 join table_task as T1 on T1.Id=D1.IdBeforeTask WHERE T1.Status!=11)),
(SELECT COUNT(T.Status = 2) FROM table_task as T WHERE T.IdGroup = G.Id)
FROM
table_group as G
The problem is I obtain this :
Group.Id, NB_TASK_TOTAL, NB_TASK_CREATED, NB_TASK_UNSURE
1 3 1 3
2 3 0 3
(I have 4 group, each group containing 3 task, all the task with Status = 1 (CREATED) and the dependency set in order to have just on "resolved" dependency so i should have
Group.Id, NB_TASK_TOTAL, NB_TASK_CREATED, NB_TASK_UNSURE
1 3 1 0
2 3 1 0
instead.
I'm a beginner in MySQL, and i'm lost on this one request.
This should do it for you:
SELECT T.IdGroup as Group_Id,
COUNT(T.IdGroup) as NB_TASK_TOTAL,
(SELECT COUNT(Tt.Id) FROM table_task Tt WHERE Tt.IdGroup = T.IdGroup AND Tt.Status = 1) as NB_TASK_CREATED,
(SELECT COUNT(Tt.Id) FROM table_task Tt WHERE Tt.IdGroup = T.IdGroup AND Tt.Status = 2 AND Tt.Id NOT IN (SELECT IdAfterTask from table_dependency as D1 join table_task as T1 on T1.Id=D1.IdBeforeTask WHERE T1.Status!=11)) as NB_TASK_UNSURE
FROM table_task T
GROUP BY T.IdGroup;

Condition based selecting from group_concat in Mysql query

Here is my table and sample data.
CREATE TABLE `articles`
(
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `tags`
(
`id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `article_tags`
(
`article_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL
);
INSERT INTO `tags` (`id`, `name`) VALUES
(1, 'Wap Stories'),
(2, 'App Stories');
INSERT INTO `articles` (`id`, `title`) VALUES
(1, 'USA'),
(2, 'England'),
(3, 'Germany'),
(4, 'India'),
(5, 'France'),
(6, 'Dubai'),
(7, 'Poland'),
(8, 'Japan'),
(9, 'China'),
(10, 'Australia');
INSERT INTO `article_tags` (`article_id`, `tag_id`) VALUES
(1, 1),
(1, 2),
(4, 1),
(5, 1),
(2, 2),
(2, 1),
(6, 2),
(7, 2),
(8, 1),
(9, 1),
(3, 2),
(9, 2),
(10, 2);
How can I get the below output I have tried using group_concat function. It gives all the results. But my requirement is I need to groupconcat values as
a. Combination of 1,2 can be there, only 1 can be there but 2 alone cannot be there.
b. Combination of 2,1 can be there, only 2 can be there but 1 alone cannot be there
Below is the output I need
id, title, groupconcat
--------------------------
1, USA, 1,2
2, England, 1,2
4, India, 1
5, France, 1
8, Japan, 1
9, China, 1,2
SqlFiddle Link
The query which I am using is
select id, title, group_concat(tag_id order by tag_id) as 'groupconcat' from articles a
left join article_tags att on a.id = att.article_id
where att.tag_id in (1,2)
group by article_id order by id
You can try like this
SELECT id, title, GROUP_CONCAT(tag_id ORDER BY tag_id) AS 'groupconcat'
FROM articles a
LEFT join article_tags att on a.id = att.article_id
WHERE att.tag_id in (1,2)
GROUP BY article_id
HAVING SUBSTRING_INDEX(groupconcat,',',1) !='2'
ORDER BY id

List all attributes from each element in a taxonomy in MySQL

I have a MySQL DB that needs to provide attributes associated with a taxonomy. I desire to have a list of all attributes, including "inherited attributes" for a given element in the taxonomy. I'm not an SQL expert & have learned (and plagiarized) much from this site. One thing I learned here is to use a Closure Table to represent my Hierarchy. What I need to do for my database is associate a large number of attributes to elements within hierarchy. However, I can't seem to figure out how to grab all of the attributes associated with a given node and all of its parents. I created the following example database for the purpose of this question (feel free to comment on anything about this schema, the fake data is just noise).
My example MySQL database structure looks like this:
-- 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
Assumptions:
1.All entities in the taxonomy are uniquely named. This means there is one and only one sub-type called “Fish” anywhere in any of the taxonomy trees.
2.Attributes are not unique and may repeat
GOAL:
Given the input type “Lizard” I would like a single query that returns the following list of attribute records:
1, IsAlive, 1
2, HasMaximumLifeSpan, 1
5, BreathesAir, 2
8, ColdBlooded, 4
13, HasFourLegs, 9
21, HasSkin, 9
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'
See it on sqlfiddle.
Note that your example output includes a_id = 5 (BreathesAir), which is a property of it_id = 2 (Mammal), which is not in the Lizard's ancestry.

Return only records validated against a lookup table

I'm using MySQL and have a little issue I'm struggling to find a fix for. I'm able to achieve this programatically via PHP using a few queries, but I'm sure I can do it as a single query :)
I have 3 tables:
products
product_keywords
valid_keywords
Each product has a number of keywords, these are referenced by a keyword_id in the "product_keywords" table. The "valid_keywords" table contains only the keywords that are allowed (i.e. as the look-up table). I need to return ONLY the products that have the keywords that match those in the "valid_keywords" table.
The valid products must not have any keywords that are not in the "valid_keywords" table.
Here are some test tables/records:
-- Table structure for table products
CREATE TABLE `products` (
`prod_id` int(11) NOT NULL,
`prod_name` varchar(10) NOT NULL,
KEY `prod_id` (`prod_id`)
);
-- Data for table products
INSERT INTO `products` (`prod_id`, `prod_name`) VALUES(1, 'Prod 1');
INSERT INTO `products` (`prod_id`, `prod_name`) VALUES(2, 'Prod 2');
INSERT INTO `products` (`prod_id`, `prod_name`) VALUES(3, 'Prod 3');
INSERT INTO `products` (`prod_id`, `prod_name`) VALUES(4, 'Prod 4');
-- Table structure for table product_keywords
CREATE TABLE `product_keywords` (
`prod_id` int(11) NOT NULL,
`keyword_id` int(11) NOT NULL,
KEY `prod_id` (`prod_id`),
KEY `keyword_id` (`keyword_id`)
);
-- Data for table product_keywords
INSERT INTO `product_keywords` (`prod_id`, `keyword_id`) VALUES(1, 1);
INSERT INTO `product_keywords` (`prod_id`, `keyword_id`) VALUES(1, 2);
INSERT INTO `product_keywords` (`prod_id`, `keyword_id`) VALUES(2, 2);
INSERT INTO `product_keywords` (`prod_id`, `keyword_id`) VALUES(2, 4);
INSERT INTO `product_keywords` (`prod_id`, `keyword_id`) VALUES(3, 4);
INSERT INTO `product_keywords` (`prod_id`, `keyword_id`) VALUES(3, 6);
INSERT INTO `product_keywords` (`prod_id`, `keyword_id`) VALUES(4, 7);
INSERT INTO `product_keywords` (`prod_id`, `keyword_id`) VALUES(4, 8);
-- Table structure for table valid_keywords
CREATE TABLE `valid_keywords` (
`keyword_id` int(11) NOT NULL,
`keyword_name` varchar(10) NOT NULL,
KEY `keyword_id` (`keyword_id`)
);
-- Data for table valid_keywords
INSERT INTO `valid_keywords` (`keyword_id`, `keyword_name`) VALUES(2, 'Keyword 2');
INSERT INTO `valid_keywords` (`keyword_id`, `keyword_name`) VALUES(4, 'Keyword 4');
INSERT INTO `valid_keywords` (`keyword_id`, `keyword_name`) VALUES(7, 'Keyword 7');
INSERT INTO `valid_keywords` (`keyword_id`, `keyword_name`) VALUES(8, 'Keyword 8');
For the example data, the query should return products 2 & 4.
Hope you guys can point me in the right direction.
Thanks.
Get the products that does not have a keyword that is not valid.
SELECT prod_id,
prod_name
FROM products
WHERE prod_id NOT IN (SELECT prod_id
FROM product_keywords
WHERE keyword_id NOT IN (SELECT keyword_id
FROM valid_keywords));
Try this one -
SELECT p.prod_id FROM products p
LEFT JOIN product_keywords pk
ON p.prod_id = pk.prod_id
LEFT JOIN valid_keywords vk
ON vk.keyword_id = pk.keyword_id
GROUP BY p.prod_id
HAVING COUNT(vk.keyword_id) = COUNT(pk.keyword_id);
+---------+
| prod_id |
+---------+
| 2 |
| 4 |
+---------+