Item(id, name, cost)
とOrders(id, bill_id, item_id, units)
というテーブルがあり、注文を追跡するために作成されます。同じbill_idは、1つの注文に属することを意味します。
Orderテーブルにitem_idとして追加する必要がある場合、その時点で)Itemは(その時点で) "利用可能"であるというDBに追加の制約を課す方法?アイテムこのシナリオでは、「利用可能」として手動で決定され、データベース内の他のフィールドから派生することはできません。
1つのスキーマ設計(私が好む)は、「利用可能」および「利用不可」フィールドを持つType列を追加することです。しかし、どのようにして外部キー制約を確認できますかitem_idは主キーだけではないはずですItem
テーブルでは、そのTypeも "Available"にする必要がありますか?
これ スタックオーバーフローの回答チェック制約を使用)は近いようですが、それが唯一の方法ですか?これはRDBMSの取るに足らないことだと思いますか、またはこれは正規化されたデータではありませんか?
他のスキーマ設計(私は好きではありません)は、「メニュー」と呼ばれるテーブルを作成することです。これには、のみアイテム使用可能)を含めることができます。問題は、このテーブルが本質的に非常に動的になり、アイテムの可用性に応じて変化し続け、状態に応じてアイテムからサブセットテーブルを作成しているだけですが、これはいいアイデアではないようです。
プログラムでこれを行うのは簡単です。ただし、RDBMSでこれをどのように実現しますか?私はデータベースがこれを処理するのに十分インテリジェントであるという考えが好きです。
元の答えは間違っています!修正されたバージョンについては、編集1を参照してください。
驚くべき解決策は、ビューの列または継承されたテーブルへの外部キーを必要としますが、残念ながらPostgreSQL(タグがあるため、RDBMSだと思います)には(まだ)ありません。
データを整理する方法の簡単な変更で十分だと思います。[ItemsAvailableQuantityのようなテーブルを作成し、Itemを注文の参照となる可用性と接続します。アイテムが利用できなくなった場合、そのアイテムからDELETE
を取得します。
CREATE TABLE Item (
id serial NOT NULL
, name text NOT NULL
, cost numeric
, PRIMARY KEY (id)
, CONSTRAINT positive_cost
CHECK (cost > 0)
);
CREATE TABLE ItemAvailableQuantity (
id serial NOT NULL
, item_id integer NOT NULL
, quantity integer NOT NULL
, PRIMARY KEY (id)
, FOREIGN KEY (item_id)
REFERENCES Item (id)
ON UPDATE CASCADE
ON DELETE CASCADE
, CONSTRAINT postive_quantity -- This constraint is the same as
CHECK (quantity > 0) -- checking something like `available = TRUE`.
);
CREATE TABLE ItemOrder ( -- Changed the name from `Order` because
id serial NOT NULL -- PostgreSQL refuses that name, somehow
, bill_id integer NOT NULL
, item_id integer NOT NULL
, units integer NOT NULL
, PRIMARY KEY (id)
, FOREIGN KEY (item_id)
REFERENCES ItemAvailableQuantity (id)
ON UPDATE CASCADE
ON DELETE CASCADE
-- Uncomment when `Bill` table is ready
-- , FOREIGN KEY (bill_id)
-- REFERENCES Bill (id)
-- ON UPDATE CASCADE
-- ON DELETE CASCADE
, CONSTRAINT positive_units
CHECK (units > 0)
);
注意!制約positive_unitsは、ソフトウェアが単位を減らして0に達すると問題を引き起こす可能性があります。CHECK >= 0
必要に応じて、または各DELETE
またはINSERT
でnitsが0(またはそれ以下)に達したときに自動的にUPDATE
- s行をトリガーするトリガーを追加します。これは、テーブルItemAvailableQuantityを保持して、実際に利用可能なアイテムのみを保持します。これは、テーブルItemOrderから参照するために必要なものです。
これで問題が解決するはずです。それはあなたの質問に対する正確な答えではありません。これには、トリガーまたはCHECK
が提供したリンクのように関数を呼び出すことが含まれます。
アイテムの数量を簡単に確認するには、ItemAvailableQuantityとItemを結合するビューを作成するだけです。本当に必要な場合は、INSERT
- able トリガー付き(黄色のボックスの警告を参照) にしてください。
実際にはOrder(別名ItemOrder)はItemAvailableQuantityではなくItemを参照して、アイテムはコメントに記載されているように、現在利用できません。
これは、テーブル全体ItemAvailableQuantityを削除し、列available_quantity on Itemのみを追加する必要があることを示唆しています。
CREATE TABLE Item (
id serial NOT NULL
, name text NOT NULL
, cost numeric
, available_quantity integer NOT NULL
, PRIMARY KEY (id)
, CONSTRAINT positive_cost
CHECK (cost > 0)
, CONSTRAINT non_negative_quantity
CHECK (quantity >= 0)
);
次に、利用可能なアイテムのみを注文に確実に挿入するために、実行できます
INSERT INTO ItemOrder (bill_id, item_id, units) VALUES
(SELECT id FROM Bill WHERE condition = something -- customize at will
, SELECT id FROM Item WHERE available_quantity >= wanted_quantity
AND other_condition = something
, wanted_quantity)
;
ここで、wanted_quantity
は、ソフトウェアからクエリに渡されるパラメーターです。
それでも問題は解決しますが、質問に対する直接の回答ではありません。