2014-04-28 2 views
2

다양한 범위의 다양한 컬럼 파티션에서 재사용하려는 일부 범위 축소 논리 (http://wiki.postgresql.org/wiki/Range_aggregation 기준)가 있습니다.매번 반복적으로 사용되지만 다른 파티션을 사용할 때마다 복잡한 윈도우 쿼리를 중앙화 할 수 있습니다.

지금 당장 PHP로이 작업을 수행하고 있습니다.

function getIntervalsQueryForPartition($partitions = array()) 
{ 
// ... there is some validation logic here, not relevant to question 

$cols = implode(', ', $partitions) . ' '; 

return <<<SQL 
SELECT $cols, MIN(start_date) start_date, MAX(end_date) end_date 
FROM (
    SELECT $cols, start_date, end_date, 
    MAX(new_start) OVER (
     PARTITION BY $cols 
     ORDER BY start_date, end_date 
    ) AS left_edge 
    FROM (
    SELECT $cols, start_date, end_date, 
    CASE WHEN GREATEST(
     MIN(start_date) OVER (
      PARTITION BY $cols 
      ORDER BY start_date, end_date 
      ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 
     ), 
     start_date - INTERVAL '90 days' 
    ) < (
    MAX(end_date) OVER (
     PARTITION BY $cols 
     ORDER BY start_date, end_date 
     ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING 
    ) 
    ) 
    THEN NULL 
    ELSE start_date 
    END AS new_start 
    FROM product_activity 
) s1 
) s2 
GROUP BY $cols, left_edge 
SQL; 
} 

가 궁극적으로 나는이 같은 윈도우를 수행 할 이상 응집 할 product_activity에 여러 컬럼 파티션이 : 나는 대체 관련 열이 실행하려는 쿼리를 반환하는 다음과 같은 기능을 가지고있다. 분명히 나는 ​​약간 다른 파티션을 가진 곳곳에 쿼리를 복사하여 붙여 넣는 것을 선호하지 않을 것이다 : 따라서 위의 PHP 함수.

포스트 그레스 내에서 완전히 동일한 추상화를 수행하려면 어떻게해야합니까? 저장 프로 시저로이 작업을 수행 할 수 있습니까? dba가 복사 및 붙여 넣기를하지 않고도 다른 파티션에 대해이 쿼리를 호출하고 열이 지정된 7 곳을 모두 편집 할 수 있기를 바랍니다.

+0

[SqlFiddle] (http://sqlfiddle.com/)에서 샘플 데이터를 준비 할 수 있습니까? – klin

+0

이것은 데이터 변환을 수행하는 방법에 관한 질문이 아니므로 어떻게 도움이 될지 모르겠습니다. 방법론에 대한보다 일반적인 질문입니다. – FoolishSeth

+0

내 대답에 만족하십니까? 질문이 있으시면 언제든지 저에게 질문하십시오. – klin

답변

1

PHP와 같은 함수를 작성할 수 있습니다. 특정 pl/pgSQL 제한 때문에 가장 간단한 옵션은 하나의 텍스트 매개 변수와 함께 함수를 작성하고 setof 레코드를 반환하는 것입니다.

create or replace function func (cols text) 
returns setof record language plpgsql as $$ 
begin 
    return query execute format (
     'SELECT %s, MIN(start_date) start_date, MAX(end_date) end_date 
     FROM (
      SELECT %s, start_date, end_date, 
      MAX(new_start) OVER (
       PARTITION BY %s 
       ORDER BY start_date, end_date 
      ) AS left_edge 
      FROM (
      SELECT %s, start_date, end_date, 
      CASE WHEN GREATEST(
       MIN(start_date) OVER (
        PARTITION BY %s 
        ORDER BY start_date, end_date 
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 
       ), 
       start_date - INTERVAL ''90 days'' 
      ) < (
      MAX(end_date) OVER (
       PARTITION BY %s 
       ORDER BY start_date, end_date 
       ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING 
      ) 
      ) 
      THEN NULL 
      ELSE start_date 
      END AS new_start 
      FROM product_activity 
     ) s1 
     ) s2 
     GROUP BY %s, left_edge', 
     cols, cols, cols, cols, cols, cols, cols); 
end $$; 

이 메서드의 유일한 단점은 함수를 호출하는 방법입니다.이 메서드는 명시 적 합성 형식으로 캐스팅되어야합니다.

select * from func('a1, a2') 
as (a1 int, a2 int, start_date date, end_date date); 

select * from func('a1, a3, a5') 
as (a1 int, a3 int, a5 int, start_date date, end_date date);