I have a table where it stores the types of discounts that a user can have.
Some users will get the standard discount, but some will get a bigger and better discount. For users who have the biggest and best discount, there will be two records in the database, one for the default discount and the other for the biggest and best discount. The biggest and best discount will be preferred in the search.
I would like to do a SELECT that would return the record with the highest discount and if you don’t find it, return it with the standard discount for me to avoid making two queries in the database or having to filter in the source code.
Ex:
| id | user_id | country | discount | cashback | free_trial |
|-----------------------------------------------------------------------|
| 1 | 1 | EUA | DEFAULT | 10 | false |
| 2 | 1 | EUA | CHRISTMAS | 20 | true |
| 3 | 3 | EUA | DEFAULT | 10 | false |
SELECT *
FROM users
WHERE country = 'EUA'
AND (discount = 'CHRISTMAS' OR discount = 'DEFAULT');
In this example above for user 1 it would return the record with the discount equal to "CHRISTMAS" and for user 3 it would return "DEFAULT" because it is the only one that has. Can you help me please?
2
Answers
You can using
GROUP BY
to do itDB Fiddle Demo
You can use the
row_number()
window function to do this. This function includes aPARTITION BY
that lets you start the numbering over with each user, as well as it’s ownORDER BY
that lets you determine which rows will sort first within each user/partition.Then you nest this inside another SELECT to limit to rows where the
row_number()
result is1
(the discount that sorted best):You could also use a LATERAL JOIN, which is usually better than the correlated join in the other answer, but not as good as the window function.