Reputation: 2347
The tabled I am presented with looks similar to this
CREATE TABLE user_status (
user_id NUMBER(10,0) PRIMARY KEY,
applied TIMESTAMP,
joined TIMESTAMP,
last_attended TIMESTAMP,
quit TIMESTAMP
);
The database is Oracle 11g.
What SQL query could use if I would like to return APPLIED, JOINED, ACTIVE or INACTIVE based on whether applied, joined, last_attended or quit is the latest and the respective date.
It is also acceptable if I can get the name of the column (instead of APPLIED, JOINED, ACTIVE or INACTIVE) that has the latest date, if that greatly simplifies the query.
Sample rows:
1 | 28-JUL-15 03.37.07 PM | 29-JUL-15 03.37.07 PM | 30-JUL-15 03.37.07 PM | (null)
2 | 18-JUL-15 03.55.24 PM | 19-JUL-15 03.55.24 PM | 20-JUL-15 03.55.24 PM | 31-JUL-15 03.55.24 PM
Expected result:
1 | ACTIVE | 30-JUL-15 03.37.07 PM
2 | INACTIVE | 31-JUL-15 03.55.24 PM
Update
Here's the solution I have based on Gordon Linoff's answer:
select (case greatest(coalesce(applied, to_date('0001-01-01', 'YYYY-MM-DD')),
coalesce(joined, to_date('0001-01-01', 'YYYY-MM-DD')),
coalesce(last_attended, to_date('0001-01-01', 'YYYY-MM-DD')),
coalesce(quit, to_date('0001-01-01', 'YYYY-MM-DD')))
when applied
then 'APPLIED'
when joined
then 'JOINED'
when last_attended
then 'INACTIVE'
when quit
then 'QUIT'
else null
end) as status, greatest(coalesce(applied, to_date('0001-01-01', 'YYYY-MM-DD')),
coalesce(joined, to_date('0001-01-01', 'YYYY-MM-DD')),
coalesce(last_attended, to_date('0001-01-01', 'YYYY-MM-DD')),
coalesce(quit, to_date('0001-01-01', 'YYYY-MM-DD'))) as status_date
from user_status;
Upvotes: 2
Views: 158
Reputation: 1269873
If all have values, you can do:
select us.*
(case when applied = greatest(applied, joined, last_attended, quit)
then 'Applied'
when joined = greatest(applied, joined, last_attended, quit)
then 'Joined'
when last_attended = greatest(applied, joined, last_attended, quit)
then 'Last Attended'
else 'Quit'
end)
from user_status us
If these could have NULL
values, then you need more complex logic, because greatest()
returns NULL
if any argument is NULL
. Assuming all are in the past, then something like this:
select (case greatest(coalesce(applied, date '0000-01-01'),
coalesce(joined, date '0000-01-01'),
coalesce(last_attended, date '0000-01-01'),
coalesce(quit, date '0000-01-01') )
when applied
then 'Applied'
when joined
then 'Joined'
when last_attended
then 'Last Attended'
else 'Quit'
end)
from . . .
Upvotes: 3
Reputation: 18410
select user_id, case greatest(applied, joined, last_attended, quit)
when applied then 'APPLIED'
when joined then 'JOINED'
when last_attended then 'ACTIVE'
when quit then 'INACTIVE' end
from user_status
In the event of a tie between fields, the first field in the case
expression wins.
Upvotes: 1
Reputation: 3344
I did it slightly different than others .. the advantage of this method is I'm also retrieving the data with it (if needed) .. ;)
insert into user_status values ( 123, sysdate-10, sysdate-9, sysdate-8, sysdate-7 );
insert into user_status values ( 234, sysdate-6, sysdate-1, sysdate-11, sysdate-16 );
insert into user_status values ( 345, sysdate-5, sysdate-2, sysdate-12, sysdate-15 );
insert into user_status values ( 456, sysdate-4, sysdate-3, sysdate-13, sysdate-14 );
commit;
with w_union as (
select applied dt, 'APPLIED' col, user_id
from user_status
union all
select joined dt, 'JOINED' col, user_id
from user_status
union all
select last_attended dt, 'LAST_ATTENDED' col, user_id
from user_status
union all
select quit dt, 'QUIT' col, user_id
from user_status
),
w_sub as (
select dt, col, user_id,
row_number() over (order by dt desc) rnum
from w_union
)
select dt, col, user_id
from w_sub
where rnum = 1
/
DT COL USER_ID
------------------------------ ------------- ----------
30-JUL-15 01.33.12.000000 PM JOINED 234
Upvotes: 0
Reputation: 70523
Does this help?
SELECT 'APPLIED', MAX(applied) as val from user_status
UNION ALL
SELECT 'JOINED', MAX(joined) as val from user_status
UNION ALL
SELECT 'ACTIVE', MAX(last_attended) as val from user_status
UNION ALL
SELECT 'INACTIVE', MAX(quit) as val from user_status
for example
you probably want to restrict this to a particular user in the innermost query...
SELECT what
FROM (
SELECT what
FROM (
SELECT 'APPLIED' as what, MAX(applied) as val from user_status
UNION ALL
SELECT 'JOINED' as what, MAX(joined) as val from user_status
UNION ALL
SELECT 'ACTIVE' as what, MAX(last_attended) as val from user_status
UNION ALL
SELECT 'INACTIVE' as what, MAX(quit) as val from user_status
) sub
ORDER BY val DESC
) sub2
WHERE rownum = 1
Upvotes: 0