a1337q
a1337q

Reputation: 780

MySQL: Select on many-to-many relation table with set of conditions

I have a many-to-many relation (MySQL) between labels and companies in an own relation table called RELcomplabel. It basically looks like this:

CREATE TABLE `RELcomplabel` (
    `IDcomplabel` INT NOT NULL AUTO_INCREMENT ,
    PRIMARY KEY (`IDcomplabel`),
    `Fcomp` INT NOT NULL ,
    `Flabel` INT NOT NULL
 );

Now I want to select all companies (all I want is Fcomp) having at least a given set of labels, e.g. Flabel = 1 AND Flabel = 2 AND Flabel = 3. If such a company is in the database, there are three rows in the table RELcomplabel, all having the same Fcomp but different Flabel (1, 2 and 3). The query should also - as good as possible - be dynamic in the number of labels, it should work for two but also for maybe ten given labels.

I found an ugly solution for two or three given labels, posted below. The problems with this solution are:

  1. The ugliness to generate it dynamically.
  2. The where-conditions on the inner joins have to check if Ftype of t0 is different with t1, t0 different with t2 and t1 different with t2.
  3. That these queries generate all possible permutations of the set (1,2,3), just to select one of it.

Solution for two labels:

SELECT s.fcomp FROM
(
    SELECT
        t0.fcomp,
        t0.ftype AS type0,
        t1.ftype AS type1
    FROM
        RELcomplabel AS t0
    INNER JOIN 
        RELcomplabel AS t1
        ON t0.fcomp = t1.fcomp
    WHERE
        t0.ftype <> t1.ftype
) AS s
WHERE
    s.type0 = 2
    AND s.type1 = 3;

Solution for three labels:

SELECT s.fcomp FROM
(
    SELECT
        t0.fcomp,
        t0.ftype AS type0,
        t1.ftype AS type1,
        t2.ftype AS type2
    FROM
        RELcomplabel AS t0
    INNER JOIN 
        RELcomplabel AS t1
        ON t0.fcomp = t1.fcomp
    INNER JOIN
        RELcomplabel AS t2
        ON t0.fcomp = t2.fcomp
    WHERE
        t0.ftype <> t1.ftype
        AND t0.ftype <> t2.ftype
        AND t1.ftype <> t2.ftype
) AS s
WHERE
    s.type0 = 1
    AND s.type1 = 2
    AND s.type2 = 3;

For example, using this testdata:

INSERT INTO `relcomplabel` (`IDcomplabel`,`Fcomp`,`Flabel`) VALUES (1,1,1);
INSERT INTO `relcomplabel` (`IDcomplabel`,`Fcomp`,`Flabel`) VALUES (2,1,2);
INSERT INTO `relcomplabel` (`IDcomplabel`,`Fcomp`,`Flabel`) VALUES (3,1,3);
INSERT INTO `relcomplabel` (`IDcomplabel`,`Fcomp`,`Flabel`) VALUES (4,2,2);
INSERT INTO `relcomplabel` (`IDcomplabel`,`Fcomp`,`Flabel`) VALUES (5,2,3);

I'm searching for a query that gives a result like

  1. Searching for all companies with labels 1 & 2:

    -------
    |Fcomp|
    -------
    | 1   |
    | 2   |
    -------
    
  2. Searching for all companies with labels 1, 2 & 3:

    -------
    |Fcomp|
    -------
    | 1   |
    -------
    

Thanks for reading this, and thanks for your help posting your approach to this problem!

Upvotes: 0

Views: 1096

Answers (1)

xception
xception

Reputation: 4287

A sqlfiddle to answer your question http://sqlfiddle.com/#!2/2711e/4

EDIT: Added SQL in case the fiddle disappears:

SELECT Fcomp
FROM RELcomplabel
WHERE Flabel IN (1, 2, 3)
GROUP BY Fcomp
HAVING COUNT(Flabel) >= 3

Upvotes: 3

Related Questions