Question

Well, maybe the title is a bit unclear, but I'm trying to order a set of people based on their geographical area AND the amount of work they're charged with (i.e. the number of projects they're working on that meet some conditions).

For this task I'm making use of 5 tables (I'll write only the relevant columns):

users
-------------------------------
ID(PK) | first_name | last_name

users_data
----------------------------------
ID(PK) | user_id(FK) | area_id(FK)

projects
---------------------
ID(PK) | agent_id(FK)

states (working phases)
-------------
ID(PK) | name

projects_states (relation table)
------------------------------------------------------------
ID(PK) | project_id(FK) | state_id(FK) | created_ad (TSTAMP)

In words: I need all the agents (agent_id) who lives in a particular area (area_id), and I need this list to be ordered by number of projects (ASC), but I need to take into consideration (for the count) only those projects wich fall into a set of states (e.g, "open", "in progress", and so on).

Example output:

[firstName] [lastName] [projectNo]
  Agent      Six        (0)
  Agent      One        (0)
  Agent      Three      (1)
  Agent      Two        (3)
  Agent      Four       (4)

I tried with this query:

SELECT COUNT(p.id) AS projectNo, u.*,
   (SELECT ps.state_id FROM project_states ps WHERE ps.project_id = p.id
    ORDER BY ps.created_at DESC LIMIT 1) AS last_state
FROM users u
JOIN users_data ud ON ud.user_id = u.id
JOIN projects p ON p.agent_id = u.id
WHERE ud.area_id = 1
GROUP BY u.id
HAVING last_state IN (4,5,6,7)
ORDER BY projectNo DESC

The query works, but of course fetches only the (very limited) number of users who have a project in that range of state. If I remove the HAVING part I get all the users (that's what I want) but produces a wrong count, since it should not count the project who are assigned to that user but are outside the range of states, i.e. if the project is in state_id 8, it needs not be counted.

I feel I'm missing something obvious, but I've been trying for sometime and can't wrap my head around it.

Was it helpful?

Solution

I would suggest that you do this with a subquery. I think this is what you want:

SELECT sum(last_state IN (4,5,6,7)) as NumProjects, u.*
FROM (SELECT u.*,
             (SELECT ps.state_id
              FROM project_states ps
              WHERE ps.project_id = p.id
              ORDER BY ps.created_at DESC
              LIMIT 1
             ) AS last_state
      FROM users u JOIN
           users_data ud
           ON ud.user_id = u.id LEFT JOIN
           projects p
           ON p.agent_id = u.id
      WHERE ud.area_id = 1
     ) u
GROUP BY u.id
ORDER BY NumProjects DESC;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top