简体   繁体   中英

SQL join and many to many queries

Given I have the following tables and records, I am interested in getting all the missions where the agency is both Nasa and Esa. I have written an inner join statement but I don't know how can I narrow this down to the result I am looking for. Just for your information I am using sqlite .

Missions Table

CREATE TABLE mission_agencies (
    id INTEGER NOT NULL, 
    name VARCHAR(250), 
    PRIMARY KEY (id)
)
id    name
1     m1
2     m2
3     m3
4     m4
5     m5

Mission Agencies Table

CREATE TABLE missions (
    _id INTEGER NOT NULL, 
    name VARCHAR(36) NOT NULL, 
    PRIMARY KEY (_id)
)
id    name
1     Nasa
2     Esa
3     Jax

Mission Ownership Table(The association table)

CREATE TABLE mission_ownership (
    mission_id INTEGER, 
    mission_agency_id INTEGER, 
    FOREIGN KEY(mission_id) REFERENCES missions (id), 
    FOREIGN KEY(mission_agency_id) REFERENCES mission_agencies (id)
)
mission_id      mission_agency_id
1               1
2               1
3               1
4               2
1               2
5               3

The current SQL statement I have is this:

SELECT *
FROM missions
INNER JOIN mission_ownership
ON missions._id = mission_ownership.mission_id
INNER JOIN mission_agencies
ON mission_agencies._id = mission_ownership.mission_agency_id

This produces a table like this:

id   name     mission_id    mission_agency_id     id    name
1    m1       1             1                     1     Nasa
2    m2       2             1                     1     Nasa
3    m3       3             1                     1     Nasa
4    m4       4             2                     2     Esa
1    m1       1             2                     2     Esa
5    m5       5             3                     3     Jax

Now I like to run a query where I ask for all the missions that have been done by both Nasa AND Esa, and the only mission satisfying this criteria is m1 , so my target result set should look like this:

id   name     mission_id    mission_agency_id     id    name
1    m1       1             1                     1     Nasa
1    m1       1             2                     2     Esa

How can I write such a query?

If you are running MySQL 8.0, here is an approach using window functions:

select *
from (
    select *, count(*) over(partition by m.id) cnt
    from missions m
    inner join mo on m.id = mo.mission_id
    inner join ma on ma.id = mo.mission_agency_id
    where ma.name in ('Nasa', 'Esa')
) t
where cnt > 1

The idea is to filter your current resultset on the agencies that you are interested in, and count how many rows remain for each mission. We can then filter on missions that have both agencies.

Note that this assumes no duplicate mission/agency.

Following the idea of filtering and counting rows as suggested down here, I found a query that works like this:

SELECT COUNT(mid), mname
FROM(
    SELECT missions._id AS mid, missions.name AS mname
    FROM missions
    INNER JOIN mission_ownership
    ON missions._id = mission_ownership.mission_id
    INNER JOIN mission_agencies
    ON mission_agencies._id = mission_ownership.mission_agency_id
    WHERE mission_agencies.name = 'Esa' or mission_agencies.name = 'Jax'
    )
GROUP BY mid
HAVING COUNT(mid) > 1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM