Question

I'm using Oracle 11g and I have a little problem over here, I hope someone can help me.

When I do execute my query;

SELECT * 
FROM myTable;

The result is:

     ID     |     VER     |     DATE
 -----------+-------------+--------------
    120     |      1      |   01/03/14
    120     |      2      |   02/03/14
    120     |      3      |   04/03/14

    110     |      1      |   01/03/14

    130     |      1      |   02/03/14
    130     |      2      |   11/03/14

I need something like this:

    ID   |   VER   |   DATE   |   VER2   |   DATE2   |   VER3   |   DATE3
---------+---------+----------+----------+-----------+----------+-----------
   120   |    1    | 01/03/14 |    2     | 02/03/14  |     3    | 04/03/14
   110   |    1    | 01/03/14 |          |           |          | 
   130   |    1    | 02/03/14 |    2     | 11/03/14  |          | 

Also at some point I'll need to SUM or rest DATE3 - DATE2 and/or DATE2 - DATE1.

Kind newbie in this forum, still don't know how it works, hope I made my self clear.

Someone told to use CASE and DECODE but honestly SQL isn't my strongest area.

thanks.

Was it helpful?

Solution

You can perform it in Oracle 11g using pivot function

 WITH TABLE1(ID, VER, DDATE) AS (
 select 120     ,      1      ,   '01/03/14' from dual union all
 select 120     ,      2      ,   '02/03/14' FROM DUAL UNION ALL
 select 120     ,      3      ,   '04/03/14' from dual union all
 select 110     ,      1      ,   '01/03/14' FROM DUAL UNION ALL
 select 130     ,      1      ,   '02/03/14' FROM DUAL UNION ALL
 SELECT 130     ,      2      ,   '11/03/14' FROM DUAL) 
 ------------
 ---- End of Data
 ------------
 SELECT * 
  FROM TABLE1
PIVOT (MIN(VER) AS VER, MIN(DDATE) FOR VER IN (1 as DATE1, 2 as DATE2, 3 as DATE3, 4 as DATE4, 5 as DATE5));

In prior version of oracle, you can use case and min

 WITH TABLE1(ID, VER, DDATE) AS (
 select 120     ,      1      ,   '01/03/14' from dual union all
 select 120     ,      2      ,   '02/03/14' FROM DUAL UNION ALL
 select 120     ,      3      ,   '04/03/14' from dual union all
 select 110     ,      1      ,   '01/03/14' FROM DUAL UNION ALL
 select 130     ,      1      ,   '02/03/14' FROM DUAL UNION ALL
 SELECT 130     ,      2      ,   '11/03/14' FROM DUAL) 
 ------------
 ---- End of Data
 ------------
 SELECT ID, 
        MIN(CASE WHEN VER = 1 THEN VER ELSE NULL END) AS VER1,
        MIN(CASE WHEN VER = 1 THEN DDATE ELSE NULL END) AS DDATE1,
        MIN(CASE WHEN VER = 2 THEN VER ELSE NULL END) AS VER2,
        MIN(CASE WHEN VER = 2 THEN DDATE ELSE NULL END) as DDATE2,
        MIN(CASE WHEN VER = 3 THEN VER ELSE NULL END) AS VER3,
        MIN(CASE WHEN VER = 3 THEN DDATE ELSE NULL END) as DDATE3,
        MIN(CASE WHEN VER = 4 THEN VER ELSE NULL END) AS VER5,
        MIN(CASE WHEN VER = 4 THEN DDATE ELSE NULL END) as DDATE4,
        MIN(CASE WHEN VER = 5 THEN VER ELSE NULL END) AS VER6,
        min(case when ver = 5 then DDATE else null end) as DDATE5
  FROM TABLE1
group by id;

Output in Both Cases is

|  ID | VER1 |   DDATE1 |   VER2 |   DDATE2 |   VER3 |   DDATE3 |   VER5 | DDATE4 |   VER6 | DDATE5 |
|-----|------|----------|--------|----------|--------|----------|--------|--------|--------|--------|
| 120 |    1 | 01/03/14 |      2 | 02/03/14 |      3 | 04/03/14 | (null) | (null) | (null) | (null) |
| 110 |    1 | 01/03/14 | (null) |   (null) | (null) |   (null) | (null) | (null) | (null) | (null) |
| 130 |    1 | 02/03/14 |      2 | 11/03/14 | (null) |   (null) | (null) | (null) | (null) | (null) |

For your table, you can use

 SELECT * 
  FROM <your table_name>
PIVOT (MIN(VER) AS VER, MIN(DDATE) FOR VER IN (1 as DATE1, 2 as DATE2, 3 as DATE3, 4 as DATE4, 5 as DATE5));

or

 SELECT ID, 
        MIN(CASE WHEN VER = 1 THEN VER ELSE NULL END) AS VER1,
        MIN(CASE WHEN VER = 1 THEN DDATE ELSE NULL END) AS DDATE1,
        MIN(CASE WHEN VER = 2 THEN VER ELSE NULL END) AS VER2,
        MIN(CASE WHEN VER = 2 THEN DDATE ELSE NULL END) as DDATE2,
        MIN(CASE WHEN VER = 3 THEN VER ELSE NULL END) AS VER3,
        MIN(CASE WHEN VER = 3 THEN DDATE ELSE NULL END) as DDATE3,
        MIN(CASE WHEN VER = 4 THEN VER ELSE NULL END) AS VER5,
        MIN(CASE WHEN VER = 4 THEN DDATE ELSE NULL END) as DDATE4,
        MIN(CASE WHEN VER = 5 THEN VER ELSE NULL END) AS VER6,
        min(case when ver = 5 then DDATE else null end) as DDATE5
  FROM <your_table_name>
group by id;

OTHER TIPS

As long as you'll only ever have a small, finite number of versions, you could do it this way (SQL Fiddle)

  WITH VER1 AS (SELECT * FROM version_data WHERE version = 1)
     , VER2 AS (SELECT * FROM version_data WHERE version = 2)
     , VER3 AS (SELECT * FROM version_data WHERE version = 3)
     , VER4 AS (SELECT * FROM version_data WHERE version = 4)
     , VER5 AS (SELECT * FROM version_data WHERE version = 5)
SELECT DISTINCT(t.version_id) AS "VERSION_ID",
       ver1.version AS "VER1",
       ver1.version_date AS "VER1_DATE",
       ver2.version AS "VER2",
       ver2.version_date AS "VER2_DATE",
       ver3.version AS "VER3",
       ver3.version_date AS "VER3_DATE",
       ver4.version AS "VER4",
       ver5.version_date AS "VER4_DATE",
       ver5.version AS "VER5",
       ver5.version_date AS "VER5_DATE"
  FROM version_data t
  LEFT JOIN VER1 ver1 ON ver1.version_id = t.version_id
  LEFT JOIN VER2 ver2 ON ver2.version_id = t.version_id
  LEFT JOIN VER3 ver3 ON ver3.version_id = t.version_id
  LEFT JOIN VER4 ver4 ON ver4.version_id = t.version_id
  LEFT JOIN VER5 ver5 ON ver5.version_id = t.version_id
 ORDER BY t.version_id
;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top