views:

53

answers:

1

Hi,

I need some help on a MySQL query I'm trying to set up. I need to find records that match conditions that are located in two different tables with a many to many relationship.

I use three tables in this query, the first contains projects, the second contains topics and the third ties them together. I want the query to find projects that are related to the topic that was selected by the user. Users can also select more than one topic to perform the search. In that case I only want to show projects that are related to both topics and not to either of them. This is what I can't figure out how to do. I expected that I'd have to do something like this but this query yields no results whilst there is a project that is linked to both topics in the database.

SELECT `projects`.*
FROM `projects`, `topics`, `projects_topics`
WHERE (`name` LIKE '%%' || `vision` LIKE '%%' || `highlights` LIKE '%%' || `optional` LIKE '%%')
    && ((`projects_topics`.`projects_id` = `projects`.`id` && `projects_topics`.`topics_id` = `topics`.`id` && `topics`.`id` = '1')
        && (`projects_topics`.`projects_id` = `projects`.`id` && `projects_topics`.`topics_id` = `topics`.`id` && `topics`.`id` = '9'))
ORDER BY `date_added` DESC

These are the tables:

projects

+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int(11)      | NO   | PRI | NULL    | auto_increment | 
| fields_id    | int(11)      | NO   | PRI | NULL    |                | 
| name         | varchar(255) | YES  |     | NULL    |                | 
| address      | varchar(255) | YES  |     | NULL    |                | 
| zip          | varchar(255) | YES  |     | NULL    |                | 
| city         | varchar(255) | YES  |     | NULL    |                | 
| state        | varchar(255) | YES  |     | NULL    |                | 
| countries_id | int(11)      | NO   | PRI | NULL    |                | 
| website      | varchar(255) | YES  |     | NULL    |                | 
| client       | varchar(255) | YES  |     | NULL    |                | 
| finished     | date         | YES  |     | NULL    |                | 
| budget       | int(11)      | YES  |     | NULL    |                | 
| vision       | text         | YES  |     | NULL    |                | 
| highlights   | text         | YES  |     | NULL    |                | 
| innovation   | text         | YES  |     | NULL    |                | 
| optional     | text         | YES  |     | NULL    |                | 
| publish      | tinyint(1)   | YES  |     | NULL    |                | 
| date         | datetime     | YES  |     | NULL    |                | 
| featured     | tinyint(1)   | YES  |     | NULL    |                | 
| frontpage    | tinyint(1)   | YES  |     | NULL    |                | 
| date_added   | datetime     | YES  |     | NULL    |                | 
+--------------+--------------+------+-----+---------+----------------+

topics

+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int(11)      | NO   | PRI | NULL    | auto_increment | 
| topic | varchar(255) | YES  |     | NULL    |                | 
| order | int(11)      | YES  |     | NULL    |                | 
+-------+--------------+------+-----+---------+----------------+

projects_topics

+-------------+---------+------+-----+---------+-------+
| Field       | Type    | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| projects_id | int(11) | NO   | PRI | NULL    |       | 
| topics_id   | int(11) | NO   | PRI | NULL    |       | 
+-------------+---------+------+-----+---------+-------+
+1  A: 
SELECT  p.*
FROM    (
        SELECT  project_id
        FROM    project_topics pt
        WHERE   topics_id IN (5, 9)
        GROUP BY
                project_id
        HAVING  COUNT(*) = 2
        ) pto
JOIN    projects p
ON      p.project_id = pto.project_id

or

SELECT  p.*
FROM    projects p
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    project_topics pt
        WHERE   pt.project_id = p.project_id
                AND pt.topic_id IN (5, 9)
        LIMIT 1 OFFSET 1
        )

Make sure that the PK in project_topics is defined as (project_id, topic_id) (in this order), or create an additional UNIQUE index on (topic_id, project_id).

Quassnoi
Let me see if I understand this correctly. For example, if users select only 1 topic, I need to set OFFSET to 0. If they select 2 topics, I need to set OFFSET to 1. If 3 topics are selected, I need to set it to 2, and so on. Correct?
Abel
@Abel: exactly.
Quassnoi