简体   繁体   中英

SQL Query to Count Distinct with Group By with a Join

There are a number of locations with members at different steps in an ordinal process. The members can be in multiple processes with different progress at one or more locations.

The join table between locations and members could look something like this called steps.

| id | member_id | step_no | location_id | process_id |
-------------------------------------------------------
| 1  | 1         | 2       | 10          | 57
| 2  | 1         | 5       | 10          | 58
| 3  | 2         | 5       | 11          | 37
| 4  | 2         | 1       | 10          | 57

I have not been able to figure how to get a unique count of members, by location, for the furthest step the member is in the process.

location_id | 1 | 2 | 3 | 4 | 5 |
---------------------------------
 10         | 1 | 0 | 0 | 0 | 1 |
 11         | 0 | 0 | 0 | 0 | 1 |

So far, I have this query:

SELECT count(DISTINCT m.id), l.id, l.name
      FROM members m
      INNER JOIN steps s ON m.id = s.member_id
      INNER JOIN locations l ON s.location_id = l.id
      WHERE step_no = 5
      GROUP BY l.id
      ORDER BY l.name

But this only returns step_no = 5, of course, and if I wrote five of these queries, the member could be counted twice at different steps.

select 
location_id
,sum(case when max_step = 1 then 1 else 0 end) as step_one_cnt
,sum(case when max_step = 2 then 1 else 0 end) as step_two_cnt
,sum(case when max_step = 3 then 1 else 0 end) as step_three_cnt
,sum(case when max_step = 4 then 1 else 0 end) as step_four_cnt
,sum(case when max_step = 5 then 1 else 0 end) as step_five_cnt
FROM
(select
s.location_id, 
s.member_id, 
max(s.step_no) as max_step
FROM steps S
group by 1,2
) as base
group by 1

Breaking it down, the base query gives you the following result:

member_id |  location_id | max_step_no
-------------------------------------------------------

| 1         | 10       | 5 
| 2         | 10       | 1
| 2         | 11       | 5

The aggregation query on this subquery (base), basically pivots the result into the form you would like to see it. The only limitation of this approach is that the number of steps is statically defined in advanced.

1- First select the following into a temp table:

select   location_id , step_no , count(member_id) as count 
into     stepsPrime
from     (select member_id, location_id, max(step_no) as step_no
          from steps 
          group by member_id, location_id ) definedTab 
group by location_id, step_no 
order by location_id;

2- Use the following query to pivot the above results:

select distinct stp.location_id,
       stp1.count as step1, 
       stp2.count as step2, 
       stp3.count as step3, 
       stp4.count as step4, 
       stp5.count as step5 
from stepsPrime stp 
left join stepsPrime stp1 on stp.location_id = stp1.location_id and stp1.step_no = 1 
left join stepsPrime stp2 on stp.location_id = stp2.location_id and stp2.step_no = 2 
left join stepsPrime stp3 on stp.location_id = stp3.location_id and stp3.step_no = 3 
left join stepsPrime stp4 on stp.location_id = stp4.location_id and stp4.step_no = 4 
left join stepsPrime stp5 on stp.location_id = stp5.location_id and stp5.step_no = 5;

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