달력

11

« 2024/11 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

'tablefunc'에 해당되는 글 1

  1. 2014.07.31 Postgresql Pivot
2014. 7. 31. 10:26

Postgresql Pivot Work/PostgreSQL2014. 7. 31. 10:26

집계 테이블을 표현 할 때 흔히 격자형 형태로 표현하기를 원하는 경우들이 있다.

이런 경우 엑셀에서는 pivot 이라는 기능을 이용한다.

데이터베이스에서도 비슷한 상황이 존재할 수 있는데, 이를 위해서 DBMS마다 약간씩 다른 방법을 제공한다. Postgresql 의 경우는 아래은 방법을 제공한다.


SELECT a::date AS cdate,

       b.desc AS TYPE,

       (random() * 10000 + 1)::int AS val

FROM generate_series((now() - '10 days'::interval)::date, now()::date, '1 day'::interval) a,

  (SELECT unnest(ARRAY['OSX', 'Windows', 'Linux']) AS DESC) b;

위의 쿼리 결과는 아래와 같다.

cdate type val
2014-07-21 OSX 3128
2014-07-21 Windows 8118
2014-07-21 Linux 6699
2014-07-22 OSX 6364
2014-07-22 Windows 4439
2014-07-22 Linux 3727
2014-07-23 OSX 6010
2014-07-23 Windows 5006
2014-07-23 Linux 2249
2014-07-24 OSX 3664
2014-07-24 Windows 2377
2014-07-24 Linux 6907
2014-07-25 OSX 6145
2014-07-25 Windows 728
2014-07-25 Linux 5920
2014-07-26 OSX 6704
2014-07-26 Windows 1331
2014-07-26 Linux 1472
2014-07-27 OSX 5668
2014-07-27 Windows 1408
2014-07-27 Linux 6162
2014-07-28 OSX 6805
2014-07-28 Windows 4762
2014-07-28 Linux 5977
2014-07-29 OSX 8917
2014-07-29 Windows 9468
2014-07-29 Linux 7261
2014-07-30 OSX 1913
2014-07-30 Windows 1495
2014-07-30 Linux 5639
2014-07-31 OSX 5195
2014-07-31 Windows 4623
2014-07-31 Linux 3756

이런 결과의 격자형 형태를 위해 아래처럼 case를 이용한 쿼리를 작성하는 방법이 일반적이다.

select cdate

, sum(case when type = 'OSX' then val else 0 end) OSX

, sum(case when type = 'Windows' then val else 0 end) Windows

, sum(case when type = 'Linux' then val else 0 end) Linux

from (

SELECT a::date AS cdate,

  b.desc AS TYPE,

  (random() * 10000 + 1)::int AS val

FROM generate_series((now() - '10 days'::interval)::date, now()::date, '1 day'::interval) a,

 (SELECT unnest(ARRAY['OSX', 'Windows', 'Linux']) AS DESC) b

) a

group by cdate

order by 1;

결과는 아래와 같다.

cdate osx windows linux
2014-07-21 7095 287 1101
2014-07-22 9741 3417 3237
2014-07-23 6321 7028 9647
2014-07-24 569 8523 7655
2014-07-25 7371 4659 2482
2014-07-26 8352 9015 559
2014-07-27 604 5552 8965
2014-07-28 79 4691 1138
2014-07-29 3355 9816 2113
2014-07-30 4707 1285 2997
2014-07-31 2029 8379 3283


Postgresql 에서 제공하는 또다른 방법은 crosstab을 이용하는 벙법이다. 쿼리는 아래와 같다.

-- crosstab 을 이용하기 위한 extension 설치

CREATE EXTENSION tablefunc;


-- Query

SELECT *

FROM crosstab(

'SELECT

a cdate,

b.desc AS type,

(random() * 10000 + 1)::int AS val

FROM generate_series((now() - ''10 days''::interval)::date, now()::date, ''1 day''::interval) a,

(SELECT unnest(ARRAY[''OSX'', ''Windows'', ''Linux'']) AS DESC) b ORDER BY 1,2'

,'SELECT unnest(ARRAY[''OSX'', ''Windows'', ''Linux''])'

AS ct(cdate date, OSX int, Windows int, Linux int);

결과는 위의 case를 이용한 Query와 동일하다.


출처 : http://www.craigkerstiens.com/2013/06/27/Pivoting-in-Postgres/

참고 : http://www.postgresql.org/docs/9.1/static/tablefunc.html


:
Posted by Elick