범위의 모든 날짜에 대해 복잡한 쿼리 실행


9

주문 테이블이 있습니다

   Column   |            Type             |                      Modifiers                      
------------+-----------------------------+-----------------------------------------------------
 id         | integer                     | not null default nextval('orders_id_seq'::regclass)
 client_id  | integer                     | not null
 start_date | date                        | not null
 end_date   | date                        | 
 order_type | character varying           | not null

데이터에 client_id에 대해 중복되지 않는 스탠딩 순서가 있으며 때로는 client_id가 일치 할 때 start_date의 스탠딩 순서를 무시하는 임시 주문이 있습니다. 동일한 유형의 주문이 겹치지 않도록하는 애플리케이션 레벨 제한 사항이 있습니다.

 id | client_id | start_date |  end_date  | order_type 
----+-----------+------------+------------+------------
 17 |        11 | 2014-02-05 |            | standing
 18 |        15 | 2014-07-16 | 2015-07-19 | standing
 19 |        16 | 2015-04-01 |            | standing
 20 |        16 | 2015-07-18 | 2015-07-18 | temporary

예를 들어, 2015-07-18클라이언트 16의 경우 주문 # 19보다 우선하므로 활성 주문이므로 주문 # 20이 있습니다. 약간의 소란으로 날짜에 활성 주문 ID를 쿼리하는 효율적인 방법을 발견했습니다.

    SELECT id from (
      SELECT
        id,
        first_value(id) OVER (PARTITION BY client_id ORDER BY order_type DESC) active_order_id
      FROM orders
      WHERE start_date <= ? and (end_date is null OR end_date >= ?)
    ) active_orders
    WHERE id = active_order_id

2015-07-18자리 표시 자로 이것을 쿼리 하면

 id 
----
 17
 18
 20

이 쿼리에 대한 쿼리 계획은 다른 아이디어와 비교했을 때 (날짜에 대한 클라이언트의 임시 주문 수를 계산하는 하위 쿼리와 같이) 매우 작으며 매우 만족합니다. (테이블의 디자인, 나는 흥분하지 않습니다)

이제 날짜 범위와 활성화 된 날짜 범위에 대한 모든 활성 주문을 찾아야합니다. 예를 들어 날짜 범위가 2015-07-18~ 인 2015-07-19경우 다음 결과를 원합니다.

active_date | id 
------------+----
 2015-07-18 | 17
 2015-07-18 | 18
 2015-07-18 | 20
 2015-07-19 | 17
 2015-07-19 | 18
 2015-07-19 | 19

주문 20은 주문 19를 재 지정 2015-07-18하지만, 주문을 재지 정하지 않습니다 2015-07-19.

나는 generate_series()날짜 범위를 생성 할 수 있다는 것을 알았지 만 날짜와 주문 ID를 얻기 위해 이것과 결합하는 방법에 대한 실마리는 없습니다. 내 직감은 교차 조인이지만이 상황에서 어떻게 작동하는지 알 수 없습니다.

감사

업데이트 SQL 바이올린을 추가했습니다 .


2
예제 데이터를 보여 주시겠습니까? 이 활성 / 비활성 및 임시 항목은 처음 읽은 후에 명확하지 않습니다.
dezso

예, 명확하지 않습니다. 귀하의 검색어는 고객 당 하나의 주문을 찾을 것이며 결정적이지 않은 것 같습니다. 클라이언트에 대해 동일한 유형의 주문이 2 개 이상있는 경우 2 개 중 어느 것이 반환되는지는 임의적이며 실행마다 다릅니다. 따라서 테이블에 제한 사항이 있거나 쿼리에 올바르지 않은 것이 있습니다.
ypercubeᵀᴹ

질문에 훨씬 더 자세한 내용을 업데이트했으며 데이터에 제약이 있습니다.
reconbot

답변:


5

select distinct on창 기능 대신 사용 하고 요일에 가입하십시오.

select 
    distinct on (date, client_id) date, 
    id 
from orders
inner join generate_series('2015-07-18'::date, '2015-07-19'::date, '1 day') date
  on start_date <= date and (end_date is null or date <= end_date)
order by date, client_id, order_type desc

http://sqlfiddle.com/#!15/5a420/16/0

명확하지 않은 경우 더 자세히 설명 할 수 있습니다.


임시 주문 / 상설 주문은 다루지 않지만 조인 후에 수행 될 수 있습니다 =)
reconbot

이것은 창 쿼리에서와 동일한 순서를 지정합니다. 따라서 (날짜, client_id)의 경우 첫 번째 order_type을 알파벳 순서로 역순으로 선택합니다.
Simon Perepelitsa

내부 조인은 완벽하며 선택 구별은 창보다 훨씬 쉽게 이해하고 수행 할 수 있습니다. 윈도우 기능을 사용해서는 안되는 다른 이유는 무엇입니까?
reconbot

1
그게 다야. 생각 distinct on보다 윈도우 쿼리보다 최적화되어 있습니다. 그건 그렇고, 이것이 SQL의 일반적인 "그룹 내"문제라고 언급해야합니다. stackoverflow.com/questions/3800551/…
Simon Perepelitsa

잘 읽었습니다. 공부해야 할 것이 있습니다. 시간이 있다면 여기서 배운 것을 사용하는이 질문의 확장 버전이 있습니다. dba.stackexchange.com/questions/108767/… 그 링크에서 배운 내용으로 다시 업데이트 할 것입니다. 그리고 감사합니다
reconbot

0

단일 날짜를 매개 변수로 사용하고 주문이있는 날짜 + id 목록을 리턴하는 함수를 작성하십시오.

그런 다음 제안한대로 generate_series를 사용하고 날짜 범위에서 함수를 호출하십시오.

이는 SQL에서 복잡한 조건을 처리 할 때 일반적인 전략입니다.

아래 코드를 포함했지만 위의 SQL 답변이 훨씬 간단합니다.

기능은 다음과 같습니다.

create or replace function o( date) returns setof INT AS '
SELECT id from (
 SELECT
  id,
  first_value(id) OVER (PARTITION BY client_id ORDER BY order_type DESC) active_order_id
 FROM orders
 WHERE start_date <= $1 and (end_date is null OR end_date >= $1)
) active_orders
WHERE id = active_order_id;
' LANGUAGE sql ;

그리고 그것을 부르는 방법 :

select distinct d, o(d::date) 
from generate_series('2015-07-18'::date, '2015-07-19'::date, '1 day') as d;

SQLFiddle


2
세부 정보, 샘플 코드 등으로 해당 답변을 플러시 할 수 있습니다.이 답변은 모호하기 때문에 삭제 될 수 있습니다.
맥스 버논

예제로 바이올린을 업데이트 할 수 있습니까? sqlfiddle.com/#!15/5a420/3/0
reconbot

일부 코드를 포함하도록 답변을 업데이트했지만 위의 답변이 더 간단합니다.
돈 드레이크 21
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.