Search code examples
sqloracle-databasepivotbigdataunpivot

Data restructure using PIVOT and UNPIVOT in SQL


I have a table with the data similar to the original data. By using the original data, i want to restructure to the modified data like in the table using PIVOT or UNPIVOT in SQL.

Original Data

lot table1 table2 table3 table4 ... table28 headno
a xxa xxb xxc xxd ... xxf 1
b xxg xxe xxi xxp ... xxx 1
c xxk xxm xxr xxt ... xxu 4
... ... ... ... ... ...

result after modification

lot table table NO head no
a xxa table1 1
a xxb table2 1
a xxc table3 1
a xxd table4 1
a ... ….
b xxg table1 1
b xxe table2 1
b xxi table3 1
b xxp table4 1
b ...
c xxk table1 4

Thanks in advance.

Original data and Modified data

Original data and Modified data Updated version


Solution

  • My technique to unpivot is to abide by a general SQL standard (one that is not limited to running on a specific database).

    Un-pivoting, in that case, is about CROSS JOIN-ing the 'horizontal' table with an in-line table i consisting of the integer column i and of as many consecutive integers as there are horizontal columns to pivot - and a CASE WHEN expression to use the right column depending on the current value of i in the current result set:

    WITH
    -- your input - 5 columns work the same as 28 ...
    -- do not use in your real query.
    indata(lot,table1,table2,table3,table4,table5,headno) AS (
              SELECT 'a','xxa','xxb','xxc','xxd','xxf',1 FROM dual
    UNION ALL SELECT 'b','xxg','xxe','xxi','xxp','xxx',1 FROM dual
    UNION ALL SELECT 'c','xxk','xxm','xxr','xxt','xxu',4 FROM dual
    )
    -- real query starts here, replace following comma with "WITH"
    ,
    -- need series of integers - 28 rather than 5 in the full example ..
    i(i) AS (
              SELECT 1  FROM dual
    UNION ALL SELECT 2  FROM dual
    UNION ALL SELECT 3  FROM dual
    UNION ALL SELECT 4  FROM dual
    UNION ALL SELECT 5  FROM dual
    )
    SELECT
      lot 
    , CASE i 
        WHEN 1 THEN table1 
        WHEN 2 THEN table2 
        WHEN 3 THEN table3 
        WHEN 4 THEN table4 
        WHEN 5 THEN table5 
        ELSE NULL
       END AS tbl 
    ,  'table'||CAST(i AS VARCHAR(1)) AS table_NO
    , headno
    FROM indata CROSS JOIN i 
    ORDER BY lot,i
    -- out  lot | tbl | table_NO | headno 
    -- out -----+-----+----------+--------
    -- out  a   | xxa | table1   |      1
    -- out  a   | xxb | table2   |      1
    -- out  a   | xxc | table3   |      1
    -- out  a   | xxd | table4   |      1
    -- out  a   | xxf | table5   |      1
    -- out  b   | xxg | table1   |      1
    -- out  b   | xxe | table2   |      1
    -- out  b   | xxi | table3   |      1
    -- out  b   | xxp | table4   |      1
    -- out  b   | xxx | table5   |      1
    -- out  c   | xxk | table1   |      4
    -- out  c   | xxm | table2   |      4
    -- out  c   | xxr | table3   |      4
    -- out  c   | xxt | table4   |      4
    -- out  c   | xxu | table5   |      4