3

고객 당 마지막 순서를 선택 PostgreSQL의 :는 PostgreSQL의에서 날짜 범위

CustomerNum, OrderNum, OrderDate : 내가 3 열이있는 테이블이있다.

날짜 범위별로 각 고객별로 많은 주문이있을 수도 있고 그렇지 않을 수도 있습니다. 필요한 것은 제공된 각 날짜 범위의 각 고객에 대한 마지막 OrderNum입니다. 내가 수행 한 작업은 고객의 ResultSet을 가져와 각각 별도로 쿼리하는 것이지만 너무 많은 시간이 걸립니다.

하위 선택을 사용하여 고객을 선택한 다음 각 고객의 마지막 주문 번호를 가져 오는 방법이 있습니까? 전부

답변

7
select customernum, max(ordernum) 
from table 
where orderdate between '...' and '...' 
group by customernum 

.

+0

그것이 내가 말하려고했던 것입니다. 모두가 그 그룹을 가져 간다. –

+0

'OrderNum'이 순차 값이라고 가정하면 생성 순서가 날짜 순서와 일치하지 않을 수 있습니다 (예 : OrderDate가 생성되었을 때가 아니라 주문이 완료 될 때 표시 될 수 있음) 그리고 최종 결정 시간에 관심이 있습니다.) –

4
SELECT t1.CustomerNum, t1.OrderNum As LastOrderNum, t1.LastOrderDate 
    FROM table1 As t1 
WHERE t1.OrderDate = (SELECT MAX(t2.OrderDate) 
         FROM table1 t2 
         WHERE t1.CustomerNum = t2.CustomerNum 
          AND t2.OrderDate BETWEEN date1 AND date2) 
    AND t1.OrderDate BETWEEN date1 AND date2 
+0

이렇게하면 Postgresql은 하위 쿼리의 집계를 통해 OrderDate 범위 제약 조건을 해제 할 수 없기 때문에 외부 전체 테이블 검색 및 내부 하위 쿼리가있는 중첩 루프. AND t1.OrderDate와 date1 및 date2 사이에 Orderdate의 인덱스를 사용하여 결과 집합을 제한 할 수 있습니다. –

+0

@Ants : 중첩 루프 조인에서 외부 테이블로 하위 쿼리를 사용하기에 Postgre가 실제로 똑똑하지 않습니까? – erikkallen

0
고객 테이블의 구조 또는 관계에 대한 확실하지

,하지만이 작동합니다 : 당신이 큰 주문 번호를 의미 마지막 주문 번호에 의한 경우

SELECT Customer.Num, (
    SELECT OrderNum FROM Orders WHERE CustomerNum = Customer.Num AND OrderDate BETWEEN :start AND :end ORDER BY OrderNum DESC LIMIT 1 
) AS LastOrderNum 
FROM Customer 
0

다음 방금 고객 NUM에 대한 술어로 선택을 사용할 수 있습니다 마지막 주문 번호는 다음 각 고객에 대한 가장 큰 주문 날짜를 찾아와 함께 가입 중 하나를해야합니다 반드시 최대 규모의 주문 번호가 아닌 경우

SELECT CustomerNum, MAX(OrderNum) AS LastOrderNum 
    FROM Orders 
    WHERE 
     CustomerNum IN (SELECT CustomerNum FROM ...) 
      AND 
     OrderDate BETWEEN :first_date AND :last_date 
    GROUP BY CustomerNum 

: 그룹 결과와 최대를 선택 나머지 명령들 그는 해당 번호 (들) : 포스트 그레스에

SELECT O.CustomerNum, O.OrderNum AS LastOrderNum 
    FROM 
     (SELECT CustomerNum, MAX(OrderDate) AS OrderDate 
      FROM Orders 
      WHERE 
       OrderDate BETWEEN :first_date AND :last_date 
        AND 
       CustomerNum IN (SELECT CustomerNum FROM ...) 
      GROUP BY CustomerNum 
     ) AS CustLatest 
      INNER JOIN 
     Orders AS O USING (CustomerNum, OrderDate); 
10

당신은 또한 표준이 아닌 DISTINCT ON 절을 사용할 수 있습니다 :

SELECT DISTINCT ON (CustomerNum) CustomerNum, OrderNum, OrderDate 
    FROM Orders 
    WHERE OrderDate BETWEEN 'yesterday' AND 'today' 
    ORDER BY CustomerNum, OrderDate DESC; 

참조 http://www.postgresql.org/docs/current/static/sql-select.html#SQL-DISTINCT

+0

표준 SQL이 아닐지라도이 질문에 대한 최상의 답을 찾은 것 같습니다. – jlandercy

+0

다른 솔루션보다 빠르며, 26 백만 행 테이블에서 35 초 만에 결과를 얻었습니다. 또한 다음과 같이 그룹화되지 않은 필드에서도 작동합니다. 'DISTINCT ON (필드) * FROM ... ' –

0
-- generate some data 
DROP TABLE tmp.orders; 
CREATE TABLE tmp.orders 
    (id INTEGER NOT NULL 
    , odate DATE NOT NULL 
    , payload VARCHAR 
    ) 
    ; 
ALTER TABLE tmp.orders ADD PRIMARY KEY (id,odate); 

INSERT INTO tmp.orders(id,odate,payload) VALUES 
    (1, '2011-10-04' , 'one') 
, (1, '2011-10-24' , 'two') 
, (1, '2011-10-25' , 'three') 
, (1, '2011-10-26' , 'four') 
, (2, '2011-10-23' , 'five') 
, (2, '2011-10-24' , 'six') 
    ; 

-- CTE to the rescue ... 
WITH sel AS (
    SELECT * FROM tmp.orders 
    WHERE odate BETWEEN '2011-10-23' AND '2011-10-24' 
    ) 
SELECT * FROM sel s0 
WHERE NOT EXISTS (
    SELECT * FROM sel sx 
    WHERE sx.id = s0.id 
    AND sx.odate > s0.odate 
    ) 
    ; 

결과 :

DROP TABLE 
CREATE TABLE 
NOTICE: ALTER TABLE/ADD PRIMARY KEY will create implicit index "orders_pkey" for table "orders" 
ALTER TABLE 
INSERT 0 6 
id | odate | payload 
----+------------+--------- 
    1 | 2011-10-24 | two 
    2 | 2011-10-24 | six 
(2 rows)