Purpose
The UNPIVOT clause is used to convert columns in the query result set into rows, which is the reverse operation of PIVOT. It combines the values of multiple columns into a single column and adds a new column to indicate which original column the value comes from.
For example, if you use the PIVOT clause to expand the total salary for each department into multiple columns, you can use the UNPIVOT clause to combine these columns back into row records in the "department + salary" format.
Note
The UNPIVOT clause is only applicable in Oracle-compatible mode.
Privilege requirements
When executing a UNPIVOT query, the current user must have the SELECT privilege on the tables or views involved in the transformation. For more information about OceanBase Database privileges, see Privilege types in Oracle-compatible mode.
Syntax
unpivot_clause:
UNPIVOT [ { INCLUDE | EXCLUDE } NULLS ]
( { column | ( column [, column... ]) }
pivot_for_clause
unpivot_in_clause
)
pivot_for_clause:
FOR { column | ( column [, column... ]) }
unpivot_in_clause:
IN
( { column | ( column [, column... ]) } [ AS { literal | ( literal [, literal... ]) } ]
[, { column | ( column [, column... ]) } [ AS { literal | ( literal [, literal... ]) } ]]
)
Parameters
Parameter |
Description |
|---|---|
INCLUDE NULLS |
Optional. The value after conversion isNULLThe rows of the table are also output as result rows. |
EXCLUDE NULLS |
Optional. The value after conversion isNULLThe rows of the specified column are not output as result rows. |
column |
The column that receives the converted data, i.e., the value column. |
pivot_for_clause |
Specify the new identity column to store theINThe tag value defined in the clause. |
unpivot_in_clause |
Specify the column to convert into a row.ASThe value that specifies the label of this column in the identity columns. If you do not specify this parameter, the system assigns a default value.ASColumn names are used as label values. |
The output columns of UNPIVOT consist of three parts: the columns that did not participate in the pivot, the identifier columns specified by pivot_for_clause, and the value columns specified by unpivot_in_clause.
Notice
If you do not specify INCLUDE NULLS or EXCLUDE NULLS, OceanBase Database processes data according to the EXCLUDE NULLS option, which means rows with a value of NULL are not output. This default behavior is different from that of Oracle Database, where INCLUDE NULLS is the default. To retain NULL rows, explicitly specify INCLUDE NULLS.
Limitations
- The columns in the
unpivot_in_clausemust be convertible to the same data type; otherwise, an errorORA-01790: expression must have same datatype as corresponding expressionis returned. - Only constant expressions are supported after
AS. Tag values cannot be dynamically generated using columns or subqueries. - Currently,
UNPIVOTis not supported as an alias for a joined table. - The target table for the
UNPIVOToperation is not currently supported when it is a natural join. - After
UNPIVOT, you can continue to use clauses such asWHEREandORDER BY. In this case, these clauses act on the transformed result set.
Examples
First, create the sample table emp and insert data into it.
obclient> CREATE TABLE emp (
empno NUMBER(4),
job VARCHAR2(9),
deptno NUMBER(2),
sal NUMBER(7,2)
);
obclient> INSERT INTO emp VALUES
(7369, 'CLERK', 20, 800),
(7499, 'SALESMAN', 30, 1600),
(7521, 'SALESMAN', 30, 1250),
(7566, 'MANAGER', 20, 2975),
(7654, 'SALESMAN', 30, 1250),
(7698, 'MANAGER', 30, 2850),
(7782, 'MANAGER', 10, 2450),
(7788, 'ANALYST', 20, 3000),
(7839, 'PRESIDENT', 10, 5000),
(7844, 'SALESMAN', 30, 1500),
(7876, 'CLERK', 20, 1100),
(7900, 'CLERK', 30, 950),
(7902, 'ANALYST', 20, 3000),
(7934, 'CLERK', 10, 1300);
Example 1: Convert multiple columns into rows
First, use the PIVOT statement to expand the total salary of each department into columns and save it as a view.
obclient> CREATE VIEW emp_pivot AS
SELECT *
FROM (SELECT job, deptno, sal FROM emp)
PIVOT (
SUM(sal)
FOR deptno IN (10 AS dept_10, 20 AS dept_20, 30 AS dept_30, 40 AS dept_40)
);
obclient> SELECT * FROM emp_pivot;
The query result is as follows:
+-----------+---------+---------+---------+---------+
| JOB | DEPT_10 | DEPT_20 | DEPT_30 | DEPT_40 |
+-----------+---------+---------+---------+---------+
| CLERK | 1300 | 1900 | 950 | NULL |
| SALESMAN | NULL | NULL | 5600 | NULL |
| MANAGER | 2450 | 2975 | 2850 | NULL |
| ANALYST | NULL | 6000 | NULL | NULL |
| PRESIDENT | 5000 | NULL | NULL | NULL |
+-----------+---------+---------+---------+---------+
5 rows in set
Then use UNPIVOT to convert the four columns DEPT_10, DEPT_20, DEPT_30, and DEPT_40 back into rows, and use AS to specify the values for the identifier column.
obclient> SELECT *
FROM emp_pivot
UNPIVOT (
sal
FOR deptno IN (dept_10 AS 10, dept_20 AS 20, dept_30 AS 30, dept_40 AS 40)
)
ORDER BY deptno, job;
The query result is as follows:
+-----------+--------+------+
| JOB | DEPTNO | SAL |
+-----------+--------+------+
| CLERK | 10 | 1300 |
| MANAGER | 10 | 2450 |
| PRESIDENT | 10 | 5000 |
| ANALYST | 20 | 6000 |
| CLERK | 20 | 1900 |
| MANAGER | 20 | 2975 |
| CLERK | 30 | 950 |
| MANAGER | 30 | 2850 |
| SALESMAN | 30 | 5600 |
+-----------+--------+------+
9 rows in set
The values in the DEPT_40 column are all NULL. According to the default EXCLUDE NULLS behavior, rows where SAL is NULL (including the five rows corresponding to the DEPT_40 column) will not appear in the result. Therefore, the result has only 9 rows. If you want to retain these rows, explicitly specify INCLUDE NULLS after UNPIVOT. In this case, the number of result rows increases from 9 to 20.
Example 2: Do not specify the tag value
When AS is not specified, the value of the identifier column is the original column name.
obclient> SELECT *
FROM (
SELECT 1 AS id, 'Laptop' AS product, 100 AS q1, 150 AS q2 FROM dual
)
UNPIVOT (
amount FOR quarter IN (q1, q2)
);
The query result is as follows:
+------+---------+--------+---------+
| ID | PRODUCT | QUARTER | AMOUNT |
+------+---------+--------+---------+
| 1 | Laptop | Q1 | 100 |
| 1 | Laptop | Q2 | 150 |
+------+---------+--------+---------+
2 rows in set