简体   繁体   中英

ORACLE select query with order by case ASC and DESC

I have data like this:

ID | FTIME                 | STATUS
1  | 2020-02-27 08:11:12   | C-in
1  | 2020-02-27 08:11:15   | C-in
1  | 2020-02-27 08:11:18   | C-in
1  | 2020-02-27 17:11:01   | C-out
1  | 2020-02-27 17:11:03   | C-out
1  | 2020-02-27 17:11:08   | C-out

Assume the table name is TBL_RECORD

Now I need distinct to get data only with this case below:

  1. For status C-in, only get data ascending, means it will be 2020-02-27 08:11:12
  2. For status C-out, only get data descending, means it will be 2020-02-27 17:11:08

So the result will be:

ID | FTIME                  | STATUS
1  | 2020-02-27 08:11:12    | C-in
1  | 2020-02-27 17:11:08    | C-out

I have tried my below code but it's not working.

SELECT DISTINCT ID, FTIME, STATUS FROM TBL_RECORD ORDER BY (CASE STATUS
          WHEN 'C-in' THEN FTIME ASC
          WHEN 'C-out' THEN FTIME DESC
      END) DESC

Is there any way to get the lucky query?

I think, we have to restrict number of records in output so we have to use group by instead of order by . Please try below query -

SELECT
    ID,
    (CASE STATUS WHEN 'C-in' THEN MIN(FTIME) ELSE MAX(FTIME) END) AS FTIME,
    STATUS
FROM TBL_RECORD
GROUP BY ID, STATUS;

I think you need below query ( Group by data by Status only)-

SELECT
    (CASE STATUS WHEN 'C-in' THEN MIN(FTIME) ELSE MAX(FTIME) END) AS FTIME,
    STATUS
FROM TBL_RECORD
GROUP BY STATUS;

If you need data only for ID = 1 then you have to add Where clause in query like below -

SELECT
    ID,
    (CASE STATUS WHEN 'C-in' THEN MIN(FTIME) ELSE MAX(FTIME) END) AS FTIME,
    STATUS
FROM TBL_RECORD
WHERE ID = 1
GROUP BY ID, STATUS;

You don't say which version of Oracle.

In Oracle 12.1 you can perform a union between two SELECT s that limit to 1 row.

For example:

(
  select *
  from tbl_record
  where status = 'C-in'
  order by ftime
  fetch next 1 rows only
)
union all (
  select *
  from tbl_record
  where status = 'C-out'
  order by ftime desc
  fetch next 1 rows only
)

EDIT FOR ORACLE 10g :

In Oracle 10g you can do:

select * 
from tbl_record 
where status = 'C-in'
  and ftime = (select min(ftime) from tbl_record where status = 'C-in')
   or status = 'C-out'
  and ftime = (select max(ftime) from tbl_record where status = 'C-out')

This one will work for multiple IDs.

If you're just using ID, FTIME and STATUS, GROUP functions will work well. If you're pulling other columns please let me know and I'll show an alternative that's a bit more involved.

To get oldest by ID for C-in :

SELECT ID, STATUS, MIN(FTIME) AS OUT_FTIME
FROM TBL_RECORD
WHERE STATUS = 'C-in'
GROUP BY ID, STATUS;

To get newest by ID for C-out :

SELECT ID, STATUS, MAX(FTIME) AS OUT_FTIME
FROM TBL_RECORD
WHERE STATUS = 'C-out'
GROUP BY ID, STATUS;

To put it all together:

SELECT ID, STATUS, MIN(FTIME) AS OUT_FTIME
FROM TBL_RECORD
WHERE STATUS = 'C-in'
GROUP BY ID, STATUS
UNION SELECT ID, STATUS, MAX(FTIME) AS OUT_FTIME
FROM TBL_RECORD
WHERE STATUS = 'C-out'
GROUP BY ID, STATUS
ORDER BY ID, OUT_FTIME;

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