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
Related
In sql help i have 3 tables, table one is asset table which is as follow
id
asset_code
asset_name
asset_group
asset_quantity
1
A001
computer
4
7
2
A002
keyboard
6
4
and another table is asset_allocation
id
asset_id
allocated_quantity
allocated_location
returned
1
1
2
IT office
no
2
2
1
main hall
yes
the last table is asset_liquidated which will present assets that are no longer going to be used
id
asset_id
liquidated_quantity
1
1
1
Now lets say that i have 7 computer out of which 2 are allocated but not returned and i have 4 keyboards out of which 1 is allocated and it is returned back and 1 computer is liquidated means it is never going to be used
so now here i want to join these 3 tables and find inventory of my current stock in hand.
Now this is the query now i need to add this
where asset_allocation.returned is enum no inside this query
SELECT id,asset_code, asset_name, asset_group, asset_quantity,allocated_quantity,liquidated_quantity,
asset_quantity - COALESCE(AA.allocated_quantity, 0) - COALESCE(AL.liquidated_quantity, 0) available_quantity
FROM asset A
LEFT JOIN (SELECT asset_id, SUM(allocated_quantity) allocated_quantity
FROM asset_allocation
GROUP BY asset_id) AA ON A.id = AA.asset_id
LEFT JOIN (SELECT asset_id, SUM(liquidated_quantity) liquidated_quantity
FROM asset_liquidated
GROUP BY asset_id) AL ON A.id = AL.asset_id;
I believe what you are looking for is adding WHERE returned = 'no' in your first JOIN like so:
SELECT id,asset_code, asset_name, asset_group, asset_quantity,allocated_quantity,liquidated_quantity,
asset_quantity - COALESCE(AA.allocated_quantity, 0) - COALESCE(AL.liquidated_quantity, 0) available_quantity
FROM asset A
LEFT JOIN (SELECT asset_id, SUM(allocated_quantity) allocated_quantity
FROM asset_allocation
WHERE returned = 'no'
GROUP BY asset_id) AA ON A.id = AA.asset_id
LEFT JOIN (SELECT asset_id, SUM(liquidated_quantity) liquidated_quantity
FROM asset_liquidated
GROUP BY asset_id) AL ON A.id = AL.asset_id;
That changes the available quantity for keyboard from 3 to 4 for me
your query:
vs. mine:
I have a database with the following tables: Students, Classes, link_student_class. Where Students contains the information about the registered students and classes contains the information about the classes. As every student can attend multiple classes and every class can be attended by multiple students, I added a linking-table, for the mapping between students and classes.
Linking-Table
id | student_id | class_id
1 1 1
2 1 2
3 2 1
4 3 3
In this table both student_id as well as class_id will appear multiple times!
What I am looking for, is a SQL-Query that returns the information about all students (like in 'SELECT * FROM students') that are not attending a certain class (given by its id).
I tried the following SQL-query
SELECT * FROM `students`
LEFT JOIN(
SELECT * FROM link_student_class
WHERE class_id = $class_id
)
link_student_class ON link_student_class.student_id = students.student_id
Where $class_id is the id of the class which students i want to exclude.
In the returned object the students i want to include and those i want to exclude are different in the value of the column 'class_id'.
Those to be included have the value 'NULL' whereas those I want to exclude have a numerical value.
NOT EXISTS comes to mind:
select s.*
from students s
where not exists (select 1
from link_student_class lsc
where lsc.student_id = s.student_id and
lsc.class_id = ?
);
The ? is a placeholder for the parameter that provides the class.
you should check for NULL link_student_class.student_id
SELECT *
FROM `students`
LEFT JOIN(
SELECT *
FROM link_student_class
WHERE class_id = $class_id
) link_student_class ON link_student_class.student_id = students.student_id
where link_student_class.student_id is null
Or also a NOT IN predicate:
WITH
stud_class(id,stud_id,class_id) AS (
SELECT 1, 1,1
UNION ALL SELECT 2, 1,2
UNION ALL SELECT 3, 2,1
UNION ALL SELECT 4, 3,3
)
,
stud(stud_id,fname,lname) AS (
SELECT 1,'Arthur','Dent'
UNION ALL SELECT 2,'Ford','Prefect'
UNION ALL SELECT 3,'Tricia','McMillan'
UNION ALL SELECT 4,'Zaphod','Beeblebrox'
)
SELECT
s.*
FROM stud s
WHERE stud_id NOT IN (
SELECT
stud_id
FROM stud_class
WHERE class_id= 2
);
-- out stud_id | fname | lname
-- out ---------+--------+------------
-- out 3 | Tricia | McMillan
-- out 4 | Zaphod | Beeblebrox
-- out 2 | Ford | Prefect
-- out (3 rows)
-- out
-- out Time: First fetch (3 rows): 9.516 ms. All rows formatted: 9.550 ms
I'm struggling with this MySql query.
I have 3 tables.
member
idMember memberEmail
1 joe#dalton.com
2 jack#dalton.com
3 lucky#luke.com
team
idTeam teamName
1 King
2 Lion
3 Cat
teamMember
idMember idTeam
1 1
2 1
3 2
3 3
I need a query that return the team the idMember is not registered.
eg: idMember 1 , not regestered in Team 2 and 3.
any idea?
best regards
Maybe something like this?
SELECT * FROM [team] T
WHERE NOT EXISTS ( SELECT 1 FROM teamMember TM WHERE idMember = [1] AND T.idTeam = TM.idTeam )
Replace [team] with the name of the second table (team id, name) and [1] with the id member you want to search for.
If you are looking fro a particular idmember:
select t.idTeam
from team t
where not exists (select 1
from teamMember tm
where tm.teamId = t.teamId and tm.memberId = 1
);
This is called a correlated subquery. You can do something similar with not in:
select t.idTeam
from team t
where t.idTeam not in (select tm.idTeam
from teamMember tm
where tm.memberId = 1
);
However, not exists is preferable because of the way that not in handles null values in the subquery.
These are the two tables Fruit and Fruit_types.There is a m:n relationship between the two tables so we have the third table fruit_type_fruit which has the primary key from the above two tables. The tables look like this
Fruit
ID NAME
1 A
2 B
3 C
Fruit_type
ID LABEL
1 CITRIC
2 DRUPES
3 UNCATALOGUED
Fruit_type_Fruit
Fruit_id Fruit_type
1 1
1 2
1 3
2 1
3 3
Problem Statement: Some fruits even though they have a category(i.e label) get label as Uncatalogued.
For ex:-
A gets the following labels : Citric, drupes and uncatalogued.
B has citric ,
C has Uncatalogued.
Now I need a query to delete all the records which have a suitable label but still have uncatalogued label too.
In the above example
A record which is uncatalogued should be deleted and not
A Citric and Drupes neither
C Uncatalogued.
How about something like this
SQL Fiddle DEMO
DELETE ftf
FROM fruit_type_fruit ftf
WHERE Fruit_type_ID = 3
AND Fruit_ID IN
(
SELECT *
FROM (
SELECT DISTINCT Fruit_ID
FROM fruit_type_fruit f
WHERE f.Fruit_type_ID = 3
) ss
WHERE Fruit_ID IN (
SELECT *
FROM (
SELECT DISTINCT Fruit_ID
FROM fruit_type_fruit f
WHERE f.Fruit_type_ID <> 3
) s)
)
I'm trying to find the leagues (lid) where two users are apart of.
Here are my tables:
Table leagues:
*id* lname
--------------
1 Hard C
3 Fun
5 Crazy
Table match:
*userid* *lid*
-----------------
1 1
4 5
1 3
2 1
4 1
4 3
*Are primary keys
match.lid is foreign key to leagues.id (a user cannot not be part of the same league twice)
Here's what I have so far (a start):
SELECT t1.lid, t2.lname
FROM match t1
JOIN leagues t2 on t1.lid = t2.id
So far I managed to join the two tables and get the names. My ultimate goal is to show the lid's where two users are part of the same league, say userid 1 and 4.
userid 1 is a member of lid 1 and 3
userid 4 is a member of lid 5, 1, and 3
Both users meet in league(lid) 1 and 3
So I need a query that shows only the league where both users meet. Like this:
lid lname
--------------
1 Hard C
3 Fun
Since userid 1 and 4 meet in league 1 and 3, the results should show that. I can run two queries for each user and check which leagues both users meet via php, but I think it's more efficient to run one query.
SELECT m1.lid, l.lname FROM
`match` m1, `match` m2, leagues l
WHERE m1.lid = m2.lid AND m1.lid = l.id
AND m1.userid = 1
AND m2.userid = 4
There are a few ways. The most straightforward is:
SELECT id AS lid,
lname
FROM leagues
WHERE id IN
( SELECT lid
FROM match
WHERE userid = 1
)
AND id IN
( SELECT lid
FROM match
WHERE userid = 4
)
;
Another way, which is a bit less direct, but may perform better — you can try it and see — is to use JOIN:
SELECT id AS lid,
lname
FROM leagues
JOIN match AS match1
ON match1.lid = leagues.id
AND match1.userid = 1
JOIN match AS match2
ON match2.lid = leagues.id
AND match2.userid = 4
;