Reputation: 53
I would like to select one email address per user based on the following rule. If preferred_email is Y, select that email address ([email protected]). If preferred_email is not Y, use that email address. Some users may only have a preferred_email value of N. I have tried using a case statement, but it didn't return the correct result.
This is an example of the table.
user_id email_address preferred_email
25 [email protected] N
25 [email protected] Y
26 [email protected] N
27 [email protected] N
Upvotes: 0
Views: 94
Reputation:
In Oracle 12.1 and higher, this can be done easily with the match_recognize
clause, like this:
select user_id, email_address
from inputs
match_recognize (
partition by user_id
order by preferred_email desc nulls last
all rows per match
pattern ( ^x )
define x as 0 = 0
)
;
However, this solution (as well as some of the others proposed here) has a potential weakness: it relies on the explicit ordering of 'Y'
vs 'N'
, and it assumes these are the only values possible in the preferred_email
column (and also that the column is not nullable).
It would be better, if the column preferred_email
is not constrained to non nullable and only possible values 'Y'
and 'N'
, to have an order clause like
order by case preferred_email when 'Y' then 0 end [...]
Unfortunately, the match_recognize
clause can only order by columns, not by expressions. (Hoping this will be addressed in the future!) In that case, an aggregate solution using the FIRST/LAST aggregate function, as in MT0's answer, is the best choice - but with the ORDER BY clause changed accordingly.
select user_id,
max(email_address) keep (dense_rank first
order by case preferred_email when 'Y' then 0 end) as email_address
from inputs
group by user_id
;
Upvotes: 0
Reputation: 168406
SELECT user_id,
MAX( email_address ) KEEP ( DENSE_RANK FIRST ORDER BY preferred_email DESC, ROWNUM )
AS email_address
FROM your_table
GROUP BY user_id
or
SELECT user_id,
email_address
FROM (
SELECT t.*,
ROW_NUMBER() OVER ( PARTITION BY user_id
ORDER BY preferred_email DESC, ROWNUM )
AS rn
FROM your_table t
)
WHERE rn = 1;
Upvotes: 2