2016-08-24 11 views
1

私は電話帳用の簡単なデータベースを開発しようとしています。これは私が書いたものである:強く正規化されたDBにデータを挿入して整合性を維持する(Postgres)

CREATE TABLE phone 
(
    phone_id SERIAL PRIMARY KEY, 
    phone CHAR(15), 
    sub_id INT, -- subscriber id -- 
    cat_id INT -- category id -- 
); 

CREATE TABLE category 
(
    cat_id SERIAL PRIMARY KEY, -- category id -- 
    cat_name CHAR(15)  -- category name -- 
); 

CREATE TABLE subscriber 
(
    sub_id SERIAL PRIMARY KEY, 
    name CHAR(20), 
    fname CHAR(20), -- first name -- 
    lname CHAR(20), -- last name -- 
); 

CREATE TABLE address 
(
    addr_id  SERIAL PRIMARY KEY, 
    country  CHAR(20), 
    city   CHAR(20), 
    street  CHAR(20), 
    house_num  INT, 
    apartment_num INT 
); 

-- many-to-many relation -- 
CREATE TABLE sub_link 
(
    sub_id INT REFERENCES subscriber(sub_id), 
    addr_id INT 
); 

少数の人々が同じアドレスに暮らすことができると一人が、異なる時間に異なる場所に住むことができるので、私は、多対多のリレーションのリンクテーブルを作成しました。

しかし、このように強く正規化されたDBにデータを追加する方法を理解することはできず、データの整合性を維持しています。

第1の改良は、私は、このテーブルbacauseアドレステーブルの上にiniqueキーを追加しましたが、重複データを含むべきではないということでした。

CREATE TABLE address 
(
    addr_id  SERIAL PRIMARY KEY, 
    country  CHAR(20), 
    city   CHAR(20), 
    street  CHAR(20), 
    house_num  INT, 
    apartment_num INT, 
    UNIQUE (country, city, street, house_num, apartment_num) 
); 

さて問題は、DBにいくつかの人についての新しいレコードを追加する方法です。 sub_linkphoneテーブルが新たな加入者のIDを使用しなければならないので、subscriberテーブルにレコードを挿入し

  1. :私は、私はアクションの次の順序を使用すべきだと思います。

  2. sub_linkにレコードを追加する前にaddr_idが存在する必要があるため、addressテーブルにレコードを挿入してください。

  3. subscriberaddressの最後のレコードをsub_linkテーブルにリンクします。しかし、このステップで私は新しい問題を抱えています:PostgreSQLのステップ1)と2)のsub_idaddr_idをどうすれば効果的に入手できますか?

  4. 次に、phoneテーブルにレコードを挿入する必要があります。 3)のステップでは、以前のクエリからsub_idを効果的に取得する方法はわかりません。

私はPostgresの約WITHブロックを読んで、私は私の場合はそれを使用する方法を見つけ出すことはできません。

-- First record -- 
WITH t0 AS (
    WITH t1 AS (
      INSERT INTO subscriber 
      VALUES(DEFAULT, 'Twilight Sparkle', NULL, NULL) 
      RETURNING sub_id 
    ), 
    t2 AS (
      INSERT INTO address 
      VALUES(DEFAULT, 'Equestria', 'Ponyville', NULL, NULL, NULL) 
      RETURNING addr_id 
    ) 
    INSERT INTO sub_link 
    VALUES((SELECT sub_id FROM t1), (SELECT addr_id FROM t2)) 
) 
INSERT INTO phone 
VALUES (DEFAULT, '000000', (SELECT sub_id FROM t1), 1); 

をしかし、私はエラーがあります:T1 WITH:データ変更文を含む句WITH がトップレベル LINE 2でなければならないが提案のように、私がやった

UPDATE AS(INSERT INTO加入者のVALUES(DEFAULT、

答えて

0

)トップ30のテーブルからデータを挿入し、IDを参照する前にIDを挿入してください。

PostgreSQLではINSERT/UPDATE ... RETURNING idの構造を使用できます。自動的に行うORMを使用していない場合は、これが役に立ちます。

ここでの唯一のことは、ステップ2で、あなたはおそらくアドレスが既に挿入する前に存在しているかどうかを確認したいということです。

SELECT addr_id FROM address WHERE country = ? AND city = ? ... 
1

あなたがRETURNING句とWITHブロックを使用して1つのクエリでそれをすべて行うことができます。 PostgreSQL docs on INSERTを参照してください。例:

WITH t1 AS (INSERT INTO subscriber VALUES ... RETURNING sub_id), 
t2 AS (INSERT INTO address VALUES ... RETURNING addr_id) 
INSERT INTO sub_link VALUES ((SELECT sub_id FROM t1), (SELECT addr_id FROM t2)) 

この単純なフォームは、各テーブルに1つの行を挿入する場合にのみ機能します。

これは多分あなたの質問の話題ですが、私はあなたも電話テーブルの外部キー(REFERENCESを使用)のsub_idとcat_id列を作ることをお勧めします。

+0

postgresはWITHブロックに2つのシーケンシング挿入を実行できますか?これは次のようなものです: 'INSERT INTO sub_link VALUES(SELECT sub_id FROM t1)、(SELECT addr_id FROM t2))、INSERT INTO電話機の値(DEFAULT、" 1111111 "、(SELECT sub_id FROM t1)、... – memset

+0

確かに、たとえば、最後のINSERTを除くすべてのINSERTをそれ自身のWITHブロックに入れてください。それぞれのWITHブロックは、それ以前の別名を参照できます。 ))INSERT INTO phone ... ' – ASL

+0

元の投稿が更新されました。クエリが非常に複雑になりました。入れ子になった 'WITH'ブロックを使用して、'データ変更文を含むWITH節が先頭になければならない'というエラーが発生しました。 – memset

関連する問題