Reputation: 1425
I have the following tables:
project(pid integer primary key, title varchar(30), finished boolean)
action(aid integer primary key, title varchar(30), finished boolean)
project_action(pid integer, aid integer, primary key(pid, aid))
A project can consist of multiple actions and an action can only belong to none or one project. Thus the cardinatlity is (project) 0..1 <--> * (action).
How can I get just the projects, whose actions are all finished?
I tried this, but that already gives me a project if only one of its actions is finished:
SELECT pid FROM project WHERE pid IN (SELECT DISTINCT pid FROM project_action WHERE aid IN (SELECT aid FROM action WHERE action.finished = true));
Upvotes: 2
Views: 85
Reputation: 2694
SELECT p.pid FROM project p WHERE p.pid NOT IN
(SELECT pa.pid FROM project_action pa
JOIN action a ON pa.aid = a.aid
WHERE a.finished = FALSE)
Upvotes: 0
Reputation: 429
Try to select just projects without unfinished actions. You should keep in mind that this approach will give you the projects with no actions at all too.
SELECT pid FROM project WHERE pid NOT IN
(SELECT DISTINCT pid FROM project_action WHERE aid IN
(SELECT aid FROM action WHERE action.finished = false)
);
Upvotes: 0
Reputation: 48179
Although somewhat unclear about the intent of your table content, I think your structures might be a little off. Let me make a simple example of a car repair (and I am by no means an auto-body person).
Project, Repair Person "A" car.
Pre-clean
Pull dent / repair parts
Apply any filler
Sand it
Paint
IF the "Actions" are going to be consistent among multiple projects, then that table will not have the "finished" boolean flag. The flag would be specific to the one project being worked on. If I had 10 cars, I could have 3 finished completely and 7 in the works somewhere along the different phases. So, that said, I would have expected a structure more like
project(pid integer primary key, title varchar(30), finished boolean)
action(aid integer title varchar(30))
project_action(pid integer, aid integer, finished boolean, primary key(pid, aid))
Having said all that, and staying with your original structures, you could have a project with per example, 2, 3 or more actions that need to be performed on it. If ANY action is incomplete, then entire project is incomplete. I would also have an index on your "Action" table based on (pid, aid, finished)
Then do a NOT EXISTS of finished = false
SELECT
p.pid,
p.title
from
project p
where
NOT EXISTS ( select pa.pid
from project_action pa
join action a on pa.aid = a.aid
AND a.finished = false
where pa.pid = p.pid )
This is basically stating... give me all projects where there are no "FALSE" finished actions pending for the project for whatever the current project is. The EXISTS (or NOT EXISTS) stops as soon as if finds a record that qualifies the condition. So, if you had 10 things incomplete for a project, as soon as ONE was found, it is done with the qualifying WHERE and accepts or rejects the project record and moves on to the next project.
Upvotes: 1
Reputation: 141
I would join the tables:
SELECT project.pid FROM project, project_action, action
WHERE project.pid = project_action.pid
AND project_action.aid = action.aid
AND action.finished = TRUE
Upvotes: 0
Reputation: 549
Try this -
SELECT project.pid FROM project
LEFT JOIN project_action ON project_action.pid = project.pid
LEFT JOIN action ON project_action.aid = action.aid
WHERE action.finished = true
Upvotes: 0