Freitag, September 14, 2012

PIVOT Klausel

Die PIVOT-Klausel definiert Oracle in der Dokumentation für 11.2 folgendermaßen:
The pivot_clause lets you write cross-tabulation queries that rotate rows into columns, aggregating data in the process of the rotation. The output of a pivot operation typically includes more columns and fewer rows than the starting data set.
Dieser Tage hat Steward Bryson erklärt, dass die Klausel ihn bei ihrer Einführung enttäuscht hätte, da sie nur mir aggregate functions arbeitet, aber dass man diese Einschränkung in manchen Fällen durch Verwendung von Aggregaten, die auch mit Strings arbeiten, wie etwa MAX umgehen kann. Mich stört an PIVOT eher die sperrige Syntax, die aus meiner Sicht alles andere als intuitiv ist. Tom Kyte hat vor einiger Zeit ein paar Varianten zur Pivotisierung zusammengestellt, worin auch das folgende Beispiel mit Scotts EMP-Tabelle enthalten ist:

select deptno, clerk, salesman,
       manager, analyst, president
  from (select deptno, job, sal
          from emp )
 pivot( sum(sal) for job in
 ( 'CLERK' as clerk,
   'SALESMAN' as salesman,
   'MANAGER' as manager,
   'ANALYST' as analyst,
   'PRESIDENT' as president ) )
 order by deptno
/

    DEPTNO      CLERK   SALESMAN    MANAGER    ANALYST  PRESIDENT
----------    -------   --------    -------    -------  ---------
        10       1300                  2450                  5000
        20       1900                  2975       6000
        30        950       5600       2850

Gerade die ALIAS-Passage erscheint mir dabei ziemlich umständlich, und der Vorteil gegenüber der traditionellen Variante mit DECODE (oder CASE) und GROUP BY (die der Herr Kyte ebenfalls vorstellt; außerdem führt er auch noch eine obskurere Methode mit COLLECT auf) ist aus meiner Sicht nicht mehr sehr groß. Da wäre vielleicht eine übersichtlichere Definition möglich gewesen.

Im Execution Plan erscheint bei Verwendung einer PIVOT Klausel ein Step SORT GROUP BY PIVOT, statt eines einfachen GROUP BY:

SQL> set autot on
SQL> r
  1  select deptno, clerk, salesman,
  2         manager, analyst, president
  3    from (select deptno, job, sal
  4            from emp )
  5   pivot( sum(sal) for job in
  6   ( 'CLERK' as clerk,
  7     'SALESMAN' as salesman,
  8     'MANAGER' as manager,
  9     'ANALYST' as analyst,
 10     'PRESIDENT' as president ) )
 11*  order by deptno

    DEPTNO      CLERK   SALESMAN    MANAGER    ANALYST  PRESIDENT
---------- ---------- ---------- ---------- ---------- ----------
        10       1300                  2450                  5000
        20       1900                  2975       6000
        30        950       5600       2850


Ausführungsplan
----------------------------------------------------------
Plan hash value: 1018027214

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     3 |    45 |     4  (25)| 00:00:01 |
|   1 |  SORT GROUP BY PIVOT|      |     3 |    45 |     4  (25)| 00:00:01 |
|   2 |   TABLE ACCESS FULL | EMP  |    14 |   210 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

SQL> select deptno,
  2    sum( decode( job, 'CLERK', sal ) ) clerk,
  3    sum( decode( job, 'SALESMAN', sal ) ) salesman,
  4    sum( decode( job, 'MANAGER', sal ) ) manager,
  5    sum( decode( job, 'ANALYST', sal ) ) analyst,
  6    sum( decode( job, 'PRESIDENT', sal ) ) president
  7    from scott.emp
  8   group by deptno
  9   order by deptno
 10  /

    DEPTNO      CLERK   SALESMAN    MANAGER    ANALYST  PRESIDENT
---------- ---------- ---------- ---------- ---------- ----------
        10       1300                  2450                  5000
        20       1900                  2975       6000
        30        950       5600       2850


Ausführungsplan
----------------------------------------------------------
Plan hash value: 15469362

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     3 |    45 |     4  (25)| 00:00:01 |
|   1 |  SORT GROUP BY     |      |     3 |    45 |     4  (25)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| EMP  |    14 |   210 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Ob das für Performance und Ressourcennutzung einen Unterschied macht, könnte ich mir gelegentlich mal anschauen (in diesem einfachen Beispiel deutet der Plan zunächst nicht darauf hin).

Keine Kommentare:

Kommentar veröffentlichen