SELECT `t`.`action_ID`, `t1`.`prov_title` AS `prov_title_A`, `t1`.`track_no` AS `track_no_A`,
`t2`.`prov_title` AS `prov_title_B`, `t2`.`track_no` AS `track_no_B`,
`t3`.`prov_title` AS `prov_title_C`, `t3`.`track_no` AS `track_no_C`
FROM (
SELECT DISTINCT `action_ID`
FROM `action_has_providers`
) AS `t`
LEFT JOIN `action_has_providers` AS `t1`
ON `t1`.`action_ID` = `t`.`action_ID` AND `t1`.`prov_title` = 'ProvA'
LEFT JOIN `action_has_providers` AS `t2`
ON `t2`.`action_ID` = `t`.`action_ID` AND `t2`.`prov_title` = 'ProvB'
LEFT JOIN `action_has_providers` AS `t3`
ON `t3`.`action_ID` = `t`.`action_ID` AND `t3`.`prov_title` = 'ProvC'
SELECT `u`.*
FROM `users` AS `u`
JOIN `user_tags` AS `ut` ON `ut`.`user_id` = `u`.`id`
AND `ut`.`tag_id` IN (1, 2, ..., N)
GROUP BY `u`.`id`
HAVING COUNT(*) = N
SELECT `u`.*
FROM `users` AS `u`
JOIN `user_tags` AS `ut` ON `ut`.`user_id` = `u`.`id`
AND `ut`.`tag_id` IN (1, 2, ..., N)
GROUP BY `u`.`id`
HAVING COUNT(DISTINCT `ut`.`tag_id`) = N
CREATE FUNCTION SearchRoot(id INT)
BEGIN
DECLARE parent INT;
SET parent = id;
REPEAT
SET id = parent;
SET parent = (SEARCH `id_parent` FROM `table` WHERE `id` = id);
UNTIL parent > 0 END REPEAT;
RETURN id;
END