Multiple tags search query

后端 未结 4 788
深忆病人
深忆病人 2021-01-02 12:24

I working on a tag based search. I have three tables tag(id,name), tagXmedia(id,tag_id,media_id), and media(id,...). tagXmedia is the mapping table between the tag and media

4条回答
  •  生来不讨喜
    2021-01-02 12:33

    SELECT
        media1.media_id
    FROM
        (
            SELECT media_id FROM tagXmedia A INNER JOIN
            (SELECT id tag_id FROM tag WHERE name='home') B
            USING (tag_id)
        ) media1
        INNER JOIN
        (
            SELECT media_id FROM tagXmedia C INNER JOIN
            (SELECT id tag_id FROM tag WHERE name='hawaii') D
            USING (tag_id)
        ) media2
        USING (media_id)
    ;
    

    Make sure you have this index in tagXmedia:

    ALTER TABLE tagXmedia ADD UNIQUE INDEX (tag_id,media_id);
    

    Here is a test case:

    drop database if exists tagmediatest;
    create database tagmediatest;
    use tagmediatest
    CREATE TABLE media
    (
       id int not null auto_increment,
       stuff varchar(20),
       PRIMARY KEY (id)
    );
    INSERT INTO media (stuff) VALUES
    ('magazine'),('television'),('iphone'),
    ('ipad'),('IE9 Browser'),('radio');
    CREATE TABLE tag
    (
       id int not null auto_increment,
       name varchar(20),
       PRIMARY KEY (id),
       UNIQUE KEY (name)
    );
    INSERT INTO tag (name) VALUES
    ('away'),('home'),('jersery city'),('hawaii'),('nyc');
    CREATE TABLE tagXmedia
    (
       id int not null auto_increment,
       tag_id INT NOT NULL,
       media_id INT NOT NULL,
       PRIMARY KEY (id),
       UNIQUE KEY (tag_id,media_id)
    );
    INSERT INTO tagXmedia (tag_id,media_id) VALUES
    (1,1),(1,2),(1,3),(1,6),
    (2,1),(2,2),(2,4),(2,5),
    (3,5),(3,4),(3,3),(3,1),
    (4,2),(4,3),(4,5),(4,6),
    (5,2),(5,3),(5,5),(5,4);
    SELECT 
        media1.media_id 
    FROM 
        ( 
            SELECT media_id FROM tagXmedia A INNER JOIN 
            (SELECT id tag_id FROM tag WHERE name='home') B 
            USING (tag_id) 
        ) media1 
        INNER JOIN 
        ( 
            SELECT media_id FROM tagXmedia C INNER JOIN 
            (SELECT id tag_id FROM tag WHERE name='hawaii') D 
            USING (tag_id) 
        ) media2
    USING (media_id)
    ; 
    

    Here is the result:

    mysql> drop database if exists tagmediatest;
    Query OK, 3 rows affected (0.09 sec)
    
    mysql> create database tagmediatest;
    Query OK, 1 row affected (0.00 sec)
    
    mysql> use tagmediatest
    Database changed
    mysql> CREATE TABLE media
        -> (
        ->    id int not null auto_increment,
        ->    stuff varchar(20),
        ->    PRIMARY KEY (id)
        -> );
    Query OK, 0 rows affected (0.05 sec)
    
    mysql> INSERT INTO media (stuff) VALUES
        -> ('magazine'),('television'),('iphone'),
        -> ('ipad'),('IE9 Browser'),('radio');
    Query OK, 6 rows affected (0.05 sec)
    Records: 6  Duplicates: 0  Warnings: 0
    
    mysql> CREATE TABLE tag
        -> (
        ->    id int not null auto_increment,
        ->    name varchar(20),
        ->    PRIMARY KEY (id),
        ->    UNIQUE KEY (name)
        -> );
    Query OK, 0 rows affected (0.08 sec)
    
    mysql> INSERT INTO tag (name) VALUES
        -> ('away'),('home'),('jersery city'),('hawaii'),('nyc');
    Query OK, 5 rows affected (0.06 sec)
    Records: 5  Duplicates: 0  Warnings: 0
    
    mysql> CREATE TABLE tagXmedia
        -> (
        ->    id int not null auto_increment,
        ->    tag_id INT NOT NULL,
        ->    media_id INT NOT NULL,
        ->    PRIMARY KEY (id),
        ->    UNIQUE KEY (tag_id,media_id)
        -> );
    Query OK, 0 rows affected (0.06 sec)
    
    mysql> INSERT INTO tagXmedia (tag_id,media_id) VALUES
        -> (1,1),(1,2),(1,3),(1,6),
        -> (2,1),(2,2),(2,4),(2,5),
        -> (3,5),(3,4),(3,3),(3,1),
        -> (4,2),(4,3),(4,5),(4,6),
        -> (5,2),(5,3),(5,5),(5,4);
    Query OK, 20 rows affected (0.05 sec)
    Records: 20  Duplicates: 0  Warnings: 0
    
    mysql> SELECT
        ->     media1.media_id
        -> FROM
        ->     (
        ->         SELECT media_id FROM tagXmedia A INNER JOIN
        ->         (SELECT id tag_id FROM tag WHERE name='home') B
        ->         USING (tag_id)
        ->     ) media1
        ->     INNER JOIN
        ->     (
        ->         SELECT media_id FROM tagXmedia C INNER JOIN
        ->         (SELECT id tag_id FROM tag WHERE name='hawaii') D
        ->         USING (tag_id)
        ->     ) media2
        -> USING (media_id)
        -> ;
    +----------+
    | media_id |
    +----------+
    |        2 |
    |        5 |
    +----------+
    2 rows in set (0.00 sec)
    
    mysql>
    

    Note that tag_id 2 and 4 reside in media_id 2 and 5. This is why the query works.

提交回复
热议问题