1

2 つのテーブルがあるとします。

注文

order_id , ....
1, ...
2, ...

各注文には「状態履歴」があります。これは履歴テーブルに保存されます。

serial, date, order_id , order_state
10,     2012-01-01, 1,  'INIT'
11,     2012-01-02, 2,  'INIT'
12,     2012-02-03, 1,  'COMPLETED'
13,     2012-02-04, 1,  'DISPATCHED'
14,     2012-02-05, 2,  'COMPLETED'
15,     2012-02-06, 2,  'DISPATCHED'

ここで、過去の任意の時点でのすべての注文の状態を知りたいと考えています。たとえば、2012 年 2 月 5 日の注文の状態を知りたいとします。

order_id, order_state, state_date
1 ,      'DISPATCHED' , 2012-02-04
2,       'COMPLETED'  , 2012-02-05

(state_date 列はオプションです)。

アプリケーションコードで注文をループして「特定の日付の状態」を取得するよりも効率的にそれを行う1つのクエリを作成する方法はありますか?

私はPostgresqlのrank() WINDOW関数でそれをうまくやったが、ランク1のものを選ぶためだけに(指定された日付の前に)すべての履歴を取得しなければならないという事実にあまり満足していない.私の見解ではアプリのコードで実行するよりも優れているわけではありません。

SELECT *  FROM ( SELECT o.order_id,
                       h.order_state,
                       h.state_date,
                       rank() ON (PARTITION BY order_id ORDER BY h.serial DESC)
                              AS hrank
                FROM order o, history h
                WHERE
                     h.order_id = o.order_id AND
                     h.date < given_date
               ) AS rh
WHERE
   rh.hrank = 1;

私が本当に欲しいのは、私のパーティション定義にある種の LIMIT 1 ですが、それが可能かどうかはわかりません。

4

3 に答える 3

2

SQL フィドル

select distinct on (o.order_id) o.order_id, h.order_state, h.date
from
    orders o
    inner join
    history h on h.order_id = o.order_id
where
    h.date <= '2012-02-05'
order by o.order_id, h.date desc

distinct on宣言された順序に従って最初のものを返します。この場合、最新の日付です。

于 2013-04-10T13:04:11.120 に答える
1

これはより速いかもしれません:

SELECT o.order_id, 
       h.order_state,
       h.state_date,
FROM "order" o 
  JOIN history h ON h.order_id = o.order_id
WHERE h.order_date = (select max(h2.order_date)
                      from history h2
                      where h2.order_id = h.order_id 
                      and h2.order_date <= date '2012-02-05');

(注文と履歴の間の結合はここでは実際には必要ないことに注意してください。ただし、クエリの例は本当に必要なもののサブセットにすぎないと思います)

于 2013-04-10T13:08:53.453 に答える
0

NOT EXISTS() レスキュー:

SELECT o.order_id
  -- h.zserial -- you might want to see this as well
  , h.order_state
  , h.state_date
FROM zorder o
JOIN history h ON h.order_id = o.order_id
    -- You probably don't need this date comparison,
    -- ,since it is already in the subquery
WHERE h.zdate < given_date
AND NOT EXISTS (
    SELECT * FROM history nx
    WHERE nx.order_id = o.order_id
    AND nx.zdate < given_date
    AND nx.zserial > h.zserial
    );

注: 列名をキーワードと競合しない名前に変更しました。

于 2013-04-10T14:09:06.340 に答える