I have a list of people with multiple term_code values. I need to find the max for each person that has a 201930 or 201940 record. I need to take the 201930 if there is both such as the case with Bob. I then need to return other fields for each person with that term. Only the red records will be returned. Fred should not show up in the output.
Here is the query I currently have, but it grabs the 201940 record for Bob. The total number of records is correct with it, but it gets some incorrect values.
SELECT userid, term_code, race, gender
FROM mytable a JOIN (
SELECT userid, MAX(term_code) AS term_code
FROM mytable
WHERE term_code <= '201940'
GROUP BY userid
) b ON (a.userid = b.userid and a.term_code = b.term_code)
WHERE term_code IN ('201930', '201940');
Using this line seems logical to me and it gets the right value for Bob, but it cuts my results by about 30%.
WHERE term_code <= COALESCE ('201930','201940')
Any suggestions?
With NOT EXISTS
:
select m.* from mytable m
where m.term_code = (
case when not exists (select 1 from mytable where userid = m.userid and term_code = 201930)
then 201940
else 201930
end
)
Or if you only want the userid
and term_code
then you can do it with simple aggregation:
select userid, min(term_code) term_code
from mytable
where term_code in (201930, 201940)
group by userid
If you want the full row from the table then you can join to the table:
select m.*
from mytable m inner join (
select userid, min(term_code) term_code
from mytable
where term_code in (201930, 201940)
group by userid
) t on t.userid = m.userid and t.term_code = m.term_code
Or with ROW_NUMBER()
window function:
select t.userid, t.term_code, t.race, t.gender
from (
select m.*,
row_number() over (partition by userid order by term_code) rn
from mytable m
where m.term_code in (201930, 201940)
) t
where t.rn = 1
See the demo .
Results:
> USERID | TERM_CODE | RACE | GENDER
> :----- | --------: | :--- | :-----
> Bob | 201930 | null | null
> Tim | 201940 | null | null
with t (USERID, term_code ) as (
select 'Bob', 201601 from dual union all
select 'Bob', 201605 from dual union all
select 'Bob', 201609 from dual union all
select 'Bob', 202930 from dual union all
select 'Bob', 202940 from dual union all
select 'Bob', 202950 from dual union all
select 'Tom', 202940 from dual union all
select 'Tom', 201605 from dual union all
select 'Tom', 201609 from dual union all
select 'Mac', 201601 from dual union all
select 'Mac', 201605 from dual union all
select 'Mac', 201609 from dual
)
select userid, term_code from
(
SELECT t.*
, sum(case when term_code in (202930, 202940) then 1 end) over (partition by userid order by term_code) rnk
FROM t
)
where rnk = 1
USE TERM_CODE
--- ----------
Bob 202930
Tom 202940
Please note the term_code values are not the same except for the ones that you are interested in. For each USERID the term_code is ranked based on your condition using a SUM() analytic function. Once that is worked out, the outer query simply filters out the 1st ranked row produced in the inner query.
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.