2017-08-26 11 views
0

この種のデータに特別な言葉があるのか​​どうかは分かりませんが、そのコンセプトはC++ std::variantに似ています(ただし、PostgreSQLでは変種のような構造を使用するのが理想的ではありません)。PostgreSQLで可能性のあるデータを格納する理想的な方法は?

CREATE TABLE purchases (
    purchaseid bigserial, 
    buyerid bigint, 
    name text, 
    ... 
); 

各購入は、例えば、可能性の数が少ないのうちの1つを介して支払うことになります、私はいくつかの列を持つテーブルpurchasesを持っていると仮定例として

チェックまたはビットコイン。各可能性には、保存する必要のある関連フィールドがそれぞれ異なります。小切手で

お支払いは小切手番号と銀行名を保存する必要になる、とビットコインでのお支払いには、送信者のビットコインアドレスおよびアドレスビットコインリターンを保存が必要となります。

チェックインペイメントとビットコインの支払いは、異なるフィールドのために別々のテーブルに置かれるのが賢明です(PostgreSQLについての私の知識はほとんどありません)。私はそれぞれの購入のみがチェックのいずれかまたはビットコインで支払うことができることを知っていれば、このようなデータを保存(およびpurchasesの各行にそれらを関連付ける)するための理想的な方法です何

ではなく両方

+0

最も柔軟なストレージについては、JSONBを使用します。 https://stackoverflow.com/questions/22654170/explanation-of-jsonb-introduced-by-postgresql –

+0

@David「柔軟なストレージ」が必要とは思わない。 (と思う)さらに重要なのいずれか、または構築物の表現(および/または執行)ですが、JSONBは非常にこれを行いません。 – Bernard

答えて

2

このような状況のために私が取るアプローチは確かにあなたの提案通りです:小切手の詳細、ビットコインの詳細などのテーブルが必要です。これらのテーブルには購入IDが含まれている必要があり、購入テーブルにはpaymenttypeidが必要です。詳細と一緒に購入を表示したい場合 はその後、あなたが参加し、左を行う必要があります。このトリックは、現在の左の結合テーブルから選択したpaymenttypeidに応じて、ビューにcase文を入れることです。これを行うには、詳細テーブルから同じ数の列を選択し、タイプを適切に調整する必要があります。これはcase文がpaymenttypeidに基づいているため、我々は、それが常に成功する実際に知っているジョインの左側に基づいているが

SELECT p.purchasedate, 
     p.otherfields, 
     pt.description, 
     case p.paymenttype 
      WHEN 1 
       THEN bd.DetailField1 -- cast if necessary 
      WHEN 2 
       THEN cd.DetailField1 -- cast if necessary 
      END AS Detail1, 
     case p.paymenttype 
      WHEN 1 
       THEN bd.DetailField2 -- cast if necessary 
      WHEN 2 
       THEN cd.DetailField2 -- cast if necessary 
      END AS Detail2 
     FROM purchases p 
     inner join paymenttypes pt 
      on p.paymenttypeid = pt.id 
     left join bitcoindetails bd 
      on bd.purchaseid = p.id 
     left join chequedetails cd 
      on cd.purchaseid = p.id 

だからあなたのような何かを得ます。つまり、常に正しい詳細テーブルから選択しています。詳細は、paymenttypeidと一致するため、選択されたレコードの詳細テーブルに存在する必要があります。

+0

本当に強制二者択一ロジック(PostgreSQLがチェックし、ビットコインの表の両方で同じ 'purchaseid'を含むからデータベースを禁止すなわち場所)何もない場合、これが唯一の方法のように思われます。クエリでは、 'CASE'を使用しない方が良いと思いますが、別の列のフィールドを選択するだけです(他のタイプの支払いではNULLになります)。これにより、元のタイプの列を保持し、ビットコインと比較して異なる数の列をチェックできるようになります。 (バンクIDのためにちょっと変わって、列を共有するためにビットコインアドレスを返すとは思いませんか?) – Bernard

+0

@Bernardは、データをどのように表示しているかによって決まります。私はこれをかなり頻繁にやった。見出しがデータが可変であることを明確にしている限り。あなたの選択肢には、もっと多くの列が必要であるという欠点があります。最終的に "お金を払ってあなたの選択をします" –

+0

見出しを明確にすることで十分であると思われ、人間がデータベースの出力を直接読み取る方が良い方法があります。しかし、私の使用のために、データは、ユーザーにうまく設計されたHTMLを出力するWebサーバーによって要求されます。したがって、列の数に制限はありません。送信されたデータのサイズはそれほど大きくなくてはいけません(単に 'NULL's)し、Webサーバーが別の列から読みやすいようにしてください。さまざまなテーブルとpaymenttypeidを使用するようにお願いしてくれてありがとうございます - 私はこのデザインを検討します。 – Bernard

関連する問題