2011-08-12 4 views
2

간단한 SQL 쿼리를 분석하는 데 실패했습니다. 나는 PostgreSQL을 사용하지만 나의 질문은 다른 RDBMS와 관련이있다.PostgreSQL 쿼리 분해

다음 예제를 고려하십시오. 테이블 주문이 있으며 총액 한도를 초과 한 첫 주문을 찾고 싶습니다.

drop table if exists orders cascade; 

/** 
Table with clients' orders 
*/ 
create table orders(
date timestamp, 
amount integer 
/** 
Other columns omitted 
*/ 
); 

/** 
Populate with test data 
*/ 
insert into orders(date,amount) 
values 
('2011-01-01',50), 
('2011-01-02',49), 
('2011-01-03',2), 
('2011-01-04',1000); 

/** 
Selects first order that caused exceeding of limit 
*/ 
create view first_limit_exceed 
as 
select min(date) from 
(
    select o1.date 
    from orders o1, 
     orders o2 
    where o2.date<=o1.date 
    group by o1.date 
    having sum(o2.amount) > 100 
) limit_exceed; 

/** 
returns "2011-01-03 00:00:00" 
*/ 
select * from first_limit_exceed; 

이제 문제를 조금 더 세분화합시다. 우리는 일부 술어를 만족하는 행에 대해서만 전체 금액을 찾고자합니다. 우리는 그러한 술어를 많이 가지고 있으며 first_limit_exceed 뷰의 별도 버전을 만드는 것은 끔찍한 코드 중복이 될 것입니다. 그래서 우리는 매개 변수화 된 뷰를 생성하고 필터링 된 행 집합을 전달하거나 그 자체에 술어를 쓰는 방법이 필요합니다. Postgres에서는 쿼리 언어 함수를 매개 변수화 된 뷰로 사용할 수 있습니다. 그러나 Postgres는 함수가 행 집합이나 다른 함수 집합을 인수로 갖도록 허용하지 않습니다. 클라이언트 측 또는 plpgsql 함수에서 여전히 문자열 보간을 사용할 수 있지만 오류가 발생하기 쉽고 테스트 및 디버그하기가 어렵습니다. 조언이 있으십니까? 나중에 PostgreSQL 8.4과에서

+1

+1 테이블 스크립트를 게시하는 경우. @dvv는 모두 그렇습니다! – Quassnoi

+0

아마도 이것이 바보 같지만 열이 술어 결과이므로 (각 열 유형이 부울이므로) 뷰를 가질 수 있습니다. 새로운 술어를 추가하는 것은 (1) 새로운 술어로 뷰를 확장하고 (2) 코드를 변경하여 새 컬럼 이름을 선택하는 것입니다. 쿼리 로직을 상당히 단순하게 유지하지만 SQL 내에 술어를 배치합니다. –

답변

1

는 :

SELECT * 
FROM (
     SELECT *, 
       SUM(amount) OVER (ORDER BY date) AS psum 
     FROM orders 
     ) q 
WHERE psum > 100 
ORDER BY 
     date 
LIMIT 1 

내부 쿼리에 원하는 조건을 추가 :

SELECT * 
FROM (
     SELECT *, 
       SUM(amount) OVER (ORDER BY date) AS psum 
     FROM orders 
     WHERE date >= '2011-01-03' 
     ) q 
WHERE psum > 100 
ORDER BY 
     date 
LIMIT 1 
+0

빠른 답장을 보내 주셔서 감사합니다.하지만 제 질문에 대해 오해 한 것 같습니다. 내 주요 관심사는 코드 중복이었습니다. 당신은 10 개의 술어를 가지고 있다고 생각해보십시오. 조회를 10 회 복사하여 수동으로 술어를 대체 할 수 있습니다. 쿼리가 작을 때 그렇게 나쁘지는 않지만 수백 줄 길이라면 어떨까요? 백 줄을 10 번 복사하면 유지 보수가 불가능한 스파게티를 만들 수 있습니다. – dvv

+0

@dvv : 집합이나 술어도'SQL'의 첫 번째 클래스 객체가 아닙니다. 정적 쿼리에 인수로 전달할 수 없습니다.그러나 유지 관리 가능성이 속도보다 중요 할 경우 동적 인 쿼리를 작성하여 파싱 오버 헤드를 추가 할 수 있습니다. – Quassnoi

+0

@dvv :'PostgreSQL'에서 세트를 테이블 튜플이나 정의 된 레코드 또는 문자열의 배열로 직렬화하여 함수간에 전달할 수 있습니다. 그러나 쿼리를 파싱하는 것이 훨씬 더 비쌉니다. 또한 미리 정의 된 형식으로 설정해야합니다. – Quassnoi

-1

그것은 당신 같은 비트가 데이터베이스에 너무 많은 코드를 삽입하려는 소리 . 특정 술어를 만족시키는 특정 릴레이션의 행에 관심이 있다면 클라이언트 코드에서 where 절이있는 select 문을 실행하면됩니다. 술어를 매개 변수로 사용하는 뷰를 갖는 것은 sql이 이미 잘 해결 한 바퀴를 재발 명하는 것입니다.

반면에 데이터베이스에 쿼리를 저장하는 인수를 볼 수 있으므로 더 큰 보고서로 구성 할 수 있습니다. 이 두 가지는 여전히 응용 프로그램 코드에 의해 더 잘 처리됩니다. 동적 SQL 생성 (예 : sqlalchemy)에 능숙한 라이브러리를 사용하고 그런 다음 쿼리 표현 (sqlalchemy 표현식 개체는 'pickleable')을 데이터베이스에 BLOB으로 저장함으로써 이와 같은 문제에 접근 할 수 있습니다.

다른 말로하면 데이터베이스는 사실의 대표자 인이며 지식을 저장합니다. 응용 프로그램은 사용자 요청에 따라 을 실행합니다. 데이터에 대한 변환을 정의 할 때 실제로 지식을 보존하는 것이 아니라 실제 사용자의 요청을 예상하고 구현하는 것이 더 중요합니다.

뷰는 필연적으로 스키마가 변경 될 때 사용하는 것이 가장 좋기 때문에 새로운 스키마를 작동 상태로 유지할 필요가없는 이전 응용 프로그램은 그대로 둘 수 있습니다.