Warm tip: This article is reproduced from serverfault.com, please click

How do I pivot in Oracle SQL 19

发布于 2020-11-27 23:43:01

I have the following table in Oracle SQL 19:

+---------+-----------+---------------------+
| job_num | job_stage |      timestamp      |
+---------+-----------+---------------------+
| job_1   | waiting   | 2020-01-28 11:51:00 |
| job_1   | waiting   | 2020-01-28 11:52:00 |
| job_1   | waiting   | 2020-01-28 11:53:00 |
| job_1   | running   | 2020-01-28 11:54:00 |
| job_1   | running   | 2020-01-28 11:55:00 |
| job_1   | running   | 2020-01-28 11:56:00 |
| job_1   | running   | 2020-01-28 11:57:00 |
| job_1   | finishing | 2020-01-28 11:58:00 |
| job_1   | finishing | 2020-01-28 11:59:00 |
| job_2   | waiting   | 2020-01-28 11:52:00 |
| job_2   | waiting   | 2020-01-28 11:53:00 |
| job_2   | waiting   | 2020-01-28 11:54:00 |
| job_2   | waiting   | 2020-01-28 11:55:00 |
| job_2   | waiting   | 2020-01-28 11:56:00 |
| job_2   | running   | 2020-01-28 11:57:00 |
| job_2   | running   | 2020-01-28 11:58:00 |
| job_2   | running   | 2020-01-28 11:59:00 |
| job_2   | running   | 2020-01-28 12:00:00 |
| job_2   | finishing | 2020-01-28 12:01:00 |
| job_2   | finishing | 2020-01-28 12:02:00 |
| job_2   | finishing | 2020-01-28 12:03:00 |
| job_2   | finishing | 2020-01-28 12:04:00 |
+---------+-----------+---------------------+

I want to pivot it in the following way:

+---------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
| job_num |     min_waiting     |     max_waiting     |     min_running     |     max_running     |    min_finishing    |    max_finishing    |
+---------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+
| job_1   | 2020-01-28 11:51:00 | 2020-01-28 11:53:00 | 2020-01-28 11:54:00 | 2020-01-28 11:57:00 | 2020-01-28 11:58:00 | 2020-01-28 11:59:00 |
| job_2   | 2020-01-28 11:52:00 | 2020-01-28 11:56:00 | 2020-01-28 11:57:00 | 2020-01-28 12:00:00 | 2020-01-28 12:01:00 | 2020-01-28 12:04:00 |
+---------+---------------------+---------------------+---------------------+---------------------+---------------------+---------------------+

More specifically, for each job_num, for each job_stage, I want to get the minimum timestamp and maximum timestamp. Then, I want to display the minimum and maximum timestamps for each job_num.

Can someone show me how to do this efficiently in Oracle SQL 19? Any help would be greatly appreciated!

I have the following tables in SQL for your reference:

Unpivoted table is below:

with t1 as (
            select 'job_1' as job_num
                   , 'waiting' as job_stage
                   , to_date('1/28/2020 11:51', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_1' as job_num
                   , 'waiting' as job_stage
                   , to_date('1/28/2020 11:52', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_1' as job_num
                   , 'waiting' as job_stage
                   , to_date('1/28/2020 11:53', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_1' as job_num
                   , 'running' as job_stage
                   , to_date('1/28/2020 11:54', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_1' as job_num
                   , 'running' as job_stage
                   , to_date('1/28/2020 11:55', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_1' as job_num
                   , 'running' as job_stage
                   , to_date('1/28/2020 11:56', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_1' as job_num
                   , 'running' as job_stage
                   , to_date('1/28/2020 11:57', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_1' as job_num
                   , 'finishing' as job_stage
                   , to_date('1/28/2020 11:58', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_1' as job_num
                   , 'finishing' as job_stage
                   , to_date('1/28/2020 11:59', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'waiting' as job_stage
                   , to_date('1/28/2020 11:52', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'waiting' as job_stage
                   , to_date('1/28/2020 11:53', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'waiting' as job_stage
                   , to_date('1/28/2020 11:54', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'waiting' as job_stage
                   , to_date('1/28/2020 11:55', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'waiting' as job_stage
                   , to_date('1/28/2020 11:56', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'running' as job_stage
                   , to_date('1/28/2020 11:57', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'running' as job_stage
                   , to_date('1/28/2020 11:58', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'running' as job_stage
                   , to_date('1/28/2020 11:59', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'running' as job_stage
                   , to_date('1/28/2020 12:00', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'finishing' as job_stage
                   , to_date('1/28/2020 12:01', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'finishing' as job_stage
                   , to_date('1/28/2020 12:02', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'finishing' as job_stage
                   , to_date('1/28/2020 12:03', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
            union
            select 'job_2' as job_num
                   , 'finishing' as job_stage
                   , to_date('1/28/2020 12:04', 'MM/DD/YYYY HH24:MI') as timestamp
                   from dual
                )
select *
from t1
order by job_num
, timestamp

Pivoted table is below:

with t1 as (
            select 'job_1' as job_num
                   , to_date('1/28/2020 11:51', 'MM/DD/YYYY HH24:MI') as min_waiting
                   , to_date('1/28/2020 11:53', 'MM/DD/YYYY HH24:MI') as max_waiting
                   , to_date('1/28/2020 11:54', 'MM/DD/YYYY HH24:MI') as min_running
                   , to_date('1/28/2020 11:57', 'MM/DD/YYYY HH24:MI') as max_running
                   , to_date('1/28/2020 11:58', 'MM/DD/YYYY HH24:MI') as min_finishing
                   , to_date('1/28/2020 11:59', 'MM/DD/YYYY HH24:MI') as max_finishing                   
                   from dual
            union
            select 'job_2' as job_num
                   , to_date('1/28/2020 11:52', 'MM/DD/YYYY HH24:MI') as min_waiting
                   , to_date('1/28/2020 11:56', 'MM/DD/YYYY HH24:MI') as max_waiting
                   , to_date('1/28/2020 11:57', 'MM/DD/YYYY HH24:MI') as min_running
                   , to_date('1/28/2020 12:00', 'MM/DD/YYYY HH24:MI') as max_running
                   , to_date('1/28/2020 12:01', 'MM/DD/YYYY HH24:MI') as min_finishing
                   , to_date('1/28/2020 12:04', 'MM/DD/YYYY HH24:MI') as max_finishing                   
                   from dual
                )
select *
from t1
order by job_num
Questioner
Daniel Lee
Viewed
0
MT0 2020-11-28 08:18:13
SELECT *
FROM   table_name
PIVOT(
  MIN( "TIMESTAMP" ) AS min,
  MAX( "TIMESTAMP" ) AS max
  FOR job_stage IN (
    'waiting' AS waiting,
    'running' AS running,
    'finishing' AS finishing
  )
)

or:

SELECT job_num,
       MIN( CASE job_stage WHEN 'waiting' THEN "TIMESTAMP" END ) AS waiting_min,
       MAX( CASE job_stage WHEN 'waiting' THEN "TIMESTAMP" END ) AS waiting_max,
       MIN( CASE job_stage WHEN 'running' THEN "TIMESTAMP" END ) AS running_min,
       MAX( CASE job_stage WHEN 'running' THEN "TIMESTAMP" END ) AS running_max,
       MIN( CASE job_stage WHEN 'finishing' THEN "TIMESTAMP" END ) AS finishing_min,
       MAX( CASE job_stage WHEN 'finishing' THEN "TIMESTAMP" END ) AS finishing_max
FROM   table_name
GROUP BY job_num

Both of which, for your sample data, outputs:

JOB_NUM | WAITING_MIN         | WAITING_MAX         | RUNNING_MIN         | RUNNING_MAX         | FINISHING_MIN       | FINISHING_MAX      
:------ | :------------------ | :------------------ | :------------------ | :------------------ | :------------------ | :------------------
job_2   | 2020-01-28 11:52:00 | 2020-01-28 11:56:00 | 2020-01-28 11:57:00 | 2020-01-28 12:00:00 | 2020-01-28 12:01:00 | 2020-01-28 12:04:00
job_1   | 2020-01-28 11:51:00 | 2020-01-28 11:53:00 | 2020-01-28 11:54:00 | 2020-01-28 11:57:00 | 2020-01-28 11:58:00 | 2020-01-28 11:59:00

db<>fiddle here