2017-06-02 14 views
0

に参加するに基づいて、私は2つのカラムを持つ、テーブルtariffsを持っている:(tariff_id, reception)制約、別のテーブル

私は2つの列で、テーブルusersを持っている:(user_id, reception)

そして、私は2つのカラムを持つテーブルusers_tariffsを持っている:(user_id, tariff_id)

1回の受信からの料金が別の受信からユーザに割り当てられた場合を防止したいと考えています。どうやってやるの?

例えば

ユーザー:

user_id | reception 
Putin | Russia 
Trump | USA 

関税:

user_id | tariff_id 
Putin | Cheap 
+0

レセプション:)詳細はStackOverflowのを確認してくださいcontryようなものです。ヨーロッパからの人々は、米国から割当てられた関税を得ることができません。 –

+0

どのような機能的依存関係がありますか? (ユーザ、受信) - >料金表、(料金表、受信) - >ユーザと(ユーザ、料金) - > 3つすべて?サブセットは?多対多とは何ですか? 1対多とは何ですか? 1対1とは何ですか?どれが必須であるか(最低1つのエントリー)?どちらが(ゼロ以上)持つことができますか?あなたの主キーは何ですか?ユニークなものは何ですか?あなたの外来キーは何ですか? – flutter

+0

USER_IDが一意である、tariff_idがユニークで、すべての値がnullではない –

答えて

1

tariff_id | reception 
cheap  | USA 
expensive | Russia 

users_tariffsで間違った状況、安い関税は米国だけのためであるため、解決策1:外部キー制約

私は次の表の定義を前提としています。 特に、複合キーuser_tariffsでは、これはuserstariffsの多対多の関係になります。

CREATE TABLE tariffs (tariff_id int NOT NULL PRIMARY KEY, 
         reception text NOT NULL); 
CREATE TABLE users (user_id int NOT NULL PRIMARY KEY, 
        reception text NOT NULL); 
CREATE TABLE user_tariffs (tariff_id int NOT NULL REFERENCES tariffs (tariff_id), 
          user_id int NOT NULL REFERENCES users (user_id), 
          PRIMARY KEY (tariff_id, user_id)); 

は、おそらくどこかに、すべての3つの列の組み合わせを必要とし、その者は、これを作成してみましょう:

ALTER TABLE user_tariffs ADD COLUMN reception text; 
UPDATE user_tariffs a 
SET reception = b.reception 
FROM (SELECT * FROM tariffs) b 
WHERE a.tariff_id = b.tariff_id; 
ALTER TABLE user_tariffs ALTER COLUMN reception SET NOT NULL; 

今、我々はFOREIGN KEYがusers(user_id, reception)を参照して使用することができます。

CREATE UNIQUE INDEX ON tariffs (tariff_id, reception); 
ALTER TABLE user_tariffs ADD FOREIGN KEY (tariff_id, reception) 
         REFERENCES tariffs (tariff_id, reception); 

はまた、我々はtariffsにFKのREF (tariff_id, reception)を使用することができます。

CREATE UNIQUE INDEX ON users (user_id, reception); 
ALTER TABLE user_tariffs ADD FOREIGN KEY (user_id, reception) 
         REFERENCES users (user_id, reception); 

データを取り込む:あなただけ(1, 1)かを追加することができますので、あなたは、データを挿入することはできません

WITH data (user_id, tariff_id) 
     AS (VALUES (1, 2), (2, 1)), -- here is your application data 
    datas (user_id, tariff_id, reception) 
     AS (SELECT user_id, 
        tariff_id, 
        (SELECT u.reception -- reception calculated by user 
        FROM users u 
        WHERE u.user_id = d.user_id) 
      FROM data d) 
INSERT INTO user_tariffs SELECT * FROM datas ; 

を:

INSERT INTO users VALUES (1, 'cheap'), (2, 'expensive'); 
INSERT INTO tariffs VALUES (1, 'cheap'), (2, 'expensive'); 

は、今、私たちは挿入するには、次のデータ(user_id, tariff_id)を持っていると仮定(2, 2)は同じreceptionであるが、(1, 2)または(2, 1)と異なるreceptionさんの。エラーメッセージは次のとおりです。

ERROR: insert or update on table "user_tariffs" violates foreign key constraint "user_tariffs_user_id_fkey1" 
DETAIL: Key (user_id, reception)=(2, cheap) is not present in table "users". 

しかし、あなたはdata AS VALUES (1, 1), (2, 2)に挿入することができます。 私はFOREIGN KEY CONSTRAINTソリューションが望ましいと思います。

テーブルデザインを改善したい場合は、functional dependenciesを記載してください。

SOLUTION 2:

CREATE OR REPLACE FUNCTION check_reception() 
RETURNS trigger AS $$ 
DECLARE valid boolean := false; 
BEGIN 
SELECT (SELECT u.reception FROM users u WHERE u.user_id = NEW.user_id) 
    = (SELECT t.reception FROM tariffs t WHERE t.tariff_id = NEW.tariff_id) 
INTO valid FROM user_tariffs ; 
IF valid = false 
THEN RAISE EXCEPTION '(user, tariff, reception) invalid.'; 
END IF; 
RETURN NEW; 
END; $$ LANGUAGE plpgsql ; 

をし、それを登録します:TRIGGER

-- DROP TABLE user_tariffs CASCADE; 
-- DROP TABLE users CASCADE; 
-- DROP TABLE tariffs CASCADE; 
CREATE TABLE tariffs (tariff_id int NOT NULL PRIMARY KEY, 
         reception text NOT NULL); 
CREATE TABLE users (user_id int NOT NULL PRIMARY KEY, 
        reception text NOT NULL); 
CREATE TABLE user_tariffs (tariff_id int NOT NULL REFERENCES tariffs (tariff_id), 
          user_id int NOT NULL REFERENCES users (user_id), 
          PRIMARY KEY (tariff_id, user_id)); 
INSERT INTO users VALUES (1, 'cheap'), (2, 'expensive'); 
INSERT INTO tariffs VALUES (1, 'cheap'), (2, 'expensive'); 
-- table user_tariffs (user_id, tariff_id) only, without reception column. 

戻り値の型トリガーに関数を作成します

CREATE TRIGGER reception_trigger 
AFTER INSERT OR UPDATE ON user_tariffs 
FOR EACH ROW EXECUTE PROCEDURE check_reception(); 

は今(1を挿入しようと、 2)、これは(安く高価な)許可されていません:

INSERT INTO user_tariffs VALUES (1, 2); 
ERROR: (user, tariff, reception) invalid. 
KONTEXT: PL/pgSQL function check_reception() line 7 at RAISE 

しかし、我々は問題なく(安い安い)である、(1,1)を挿入することができます

トリガが、ここでは最善の解決策ではありません

INSERT INTO user_tariffs VALUES (1, 1); 
SELECT * FROM user_tariffs; 

備考私の意見。可能であれば、トリガーを避けるようにしてください。彼らは副作用(トランザクションなど)を持つことができます。

+0

違うレセプションの料金表の不正使用を防ぐ方法を理解していません。 [OK]を、してくださいインデックスがユニークであり、我々はusers_tariffsでユニークな行 'Putin-> Cheap'を持っていますが、安いがプーチンの受信のための関税は許可されていません... –

+0

あなたは例の行データを持つテーブルを追加することはできますか?問題をさらに説明するだけの行。 – flutter

+0

例が問題になっています - E.G.があります。ブロック。 –

関連する問題