2016-11-09 5 views
0

時間の経過とともにウェブサイトのアイテムの価格をうまく追跡したいのですが、 1つのオプションは、postgresql 9.5 - 時間の経過とともに値が変化する

create table prices (
    name text, 
    price decimal, 
    updated timestamp 
) 

のようなテーブルを持つだけで、価格を更新するたびにこのテーブルに新しい行が作成されます。私は価格ごとに5を更新しています

    1. 私は、任意の時点で数千個のアイテムを追跡しています: はしかし、私はこのアプローチは次のような理由から、私の状況では非常に「素敵」ではないと思います価格は通常非常に頻繁に変更されることはなく、時には変更されないこともあります。これらの理由の

    、特定の項目のために、と言う、dove bodywashは、私の価格表には、すべてが少しばかげ

    'dove soap' | 3.00 | <a new timestamp every 5 minutes> 
    

    のように見える200行を含めることができます。 私の意見では、商品が特定の価格を持っていた時間範囲を格納するprice_historyテーブルを追加するのはずっと良い解決策です。例えば、price_history

    name | price | created_at | updated_at 
    

    を持っているかもしれないし、望ましい行動は、私がdove soapの価格を更新するたびに、自動的に価格が変更されているかどうかをチェックし、トリガーがあるだろうということだろう - それはしていない場合次に、prices_historyの対応するエントリのupdated_atを変更し、もしあれば、新しい価格のprices_historyに新しい行を作成します。実行の例として、私は持っていたい:

    1)時には私はinsert into prices ('dove soap', 3.00)です。この時点で、price_history表Iはupdate prices set price = 3.00 where name = 'dove soap'を行うTIME2で)

    |'dove soap' | 3.00 | time1 | null | 
    

    2行を含むであろう。今度のprice_historyテーブルは、

    'dove soap' | 3.00 | time1 | time2 
    

    のようになります。3)時刻3に価格はまだ3.00です。 price_historyは

    のようになります。
    'dove soap' | 3.00 | time1| time3 
    

    4)時刻4の価格は3.50です。 price_historyは今のようになります。

    'dove soap' | 3.00 | time1 | time3 
    'dove soap' | 3.50 | time4 | null 
    

    私の問題は私が何を100%わからないんだけど、これはこれについて移動する良い方法であるかどうかわからないんだけど、と

    1. ですこれを実装する良い方法があります。

    上記のいずれかのアドバイスは大変ありがとうございます。

    おかげで

    編集:-):私は私が見て一つのことは、同様の価格を使用していますtemporal_tables PostgreSQLの拡張であったことを含まなければならない/ price_history /設定します。問題は、価格が更新されるたびにprice_historyテーブルに新しい行が作成され、変更されていない場合はイベントが目的を破るように見えるということです。このデフォルトの動作を変更する方法はないようですが、誰かが分かっていれば教えてください!

  • +0

    私は同様の状況があります。私のレコードはそれぞれ開始日と終了日を持っています。レコードが追加されるたびに(新しい開始日を使用して)、トリガが起動して、前のレコードの終了日が適切な日付に更新されます。あなたのケースでは、私は価格が同じ場合に挿入されない挿入前にトリガを追加します。何も変更されていなければ、updated_atの変更を気にしません。最後に、私はあなたが唯一のテーブルと現在のレコードを抽出するビューとしてprice_historyを呼んでいるでしょう。 – mlinth

    +0

    返信いただきありがとうございます!あなたはそのようなトリガを作成する例へのリンクを持っていることがありますか?私はかなりSQLに新しいですし、物事がどのように動作するのかをよく理解していません。 – ira

    答えて

    2

    ここでは、1つのテーブルとビューを使用して動作するデザインがあります...私はいくつか前提をしています。つまり、最後の更新時間を追跡するのは本当に気にしません。最新のエントリの終了時刻は2999-12-31 23:59:59です。 (空白にしておくこともできますが、null値が気に入らず、そこに日付があるとクエリ間でやり取りできます...)。

    price_history_tableを作成します。

    create table price_history(
    
    article_id integer, -- I like using article ids 
    article_name text, -- I don't like using reserved words for columns 
    price decimal not null, 
    start_time timestamp not null, 
    end_time timestamp not null default '2999-12-31 23:59:59') 
    

    (あなたは別のテーブルにあなたの商品の説明を格納してのみ保存考えるかもしれませんが、あなたは、以下を通じてarticle_nameでのarticle_idを置き換える、のarticle_idを使用しない場合ディスク上のスペースを少なくし、書き込む列を少なくします)。

    のarticle_idと終了時間に一意制約を作成します。

    alter table price_history add constraint article_id_end_time unique (article_id,end_time) 
    

    ...とのarticle_idとstart_timeの

    alter table price_history add constraint pk_price_history primary key (article_id,start_time); 
    

    の主キーを、私はそれを防ぐために、これらの制約を持つことが重要だと思います重複した時間があなたのロジックを壊すので、あなたはテーブルにゴミを入れます。

    トリガー機能が追加されました。価格が変更されていない場合はトリガーは何も行いません。それ以外の場合は、最後のレコードのend_timeが新しいstart_timeに更新されます。

    CREATE FUNCTION update_enddate() 
        RETURNS trigger 
        LANGUAGE 'plpgsql' 
        COST 100.0 
        VOLATILE NOT LEAKPROOF 
    AS $BODY$ 
    
    BEGIN 
    
    
    
        if EXISTS (select * from price_history where article_id = NEW.article_id AND end_time ='2999-12-31 23:59:59'::timestamp AND price = NEW.price) THEN 
        -- the price hasn't changed, don't do anything 
    
        RETURN NULL; 
    
        ELSE --Set the end date to the new startdate 
          update price_history set end_time = NEW.start_time where article_id = new.article_id AND end_time ='2999-12-31 23:59:59'::timestamp; 
         RETURN NEW; 
        END IF; 
    
    
    
        END; 
    
    $BODY$; 
    

    トリガー自体。

    CREATE TRIGGER trigger_update_enddate BEFORE INSERT on price_history FOR EACH ROW EXECUTE PROCEDURE update_enddate(); 
    

    最新のレコードのビュー。

    CREATE VIEW prices AS 
        SELECT article_id,article_name,price,start_time from price_history where end_time ='2999-12-31 23:59:59'::timestamp; 
    

    あなたは価格があなたは彼らが含まれているため、クエリ「間」と少し注意する必要がありますあなたが

    SELECT * from price_history where start_time <= mytime and end_time > mytime; 
    

    ノートのようなものを試すことができます与えられた更新用に変更するかどうかを知りたい場合開始点と終了点があり、あなたの時間がstart_timeに一致すると、重複を得ることができます。

    start_timeは、価格が最後に変更された時間と同じです。更新時間を別のテーブルに保存して、start_time < = update_timeとend_time> update_timeに参加して、「完全な履歴」を得ることができます。

    レコードを絶えず追加している場合は、インデックスのパフォーマンスがわからないため、インデックスを持たないとパフォーマンスが向上する可能性があります。

    +0

    非常に感謝しています。残念ながら、私は最後の更新された時間を追跡する必要があります。私はあなたのコメントを最後に見ましたが、if/elseの最初のケースで既存の行を更新するトリガー関数を変更することもできますか? – ira

    +0

    あなたはそうすることができますが、物事がどのようにうまくいくか正確に考える必要があります。 last_updatedという3番目の列が必要な場合は、トリガーを変更できます(SELECT NEW.update_time = now())。 – mlinth

    関連する問題