2016-08-24 71 views
1

我試圖爲電話簿開發一個簡單的數據庫。這是我寫的:將數據插入強歸一化的數據庫並保持完整性(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這樣的添加數據和維護數據的完整性。

第一個改進是,我加入inique鍵上的地址表bacause此表不應該包含重複的數據:

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) 
); 

現在的問題是如何增加對一些人到數據庫的新紀錄。我想我應該用行動下一順序:

  1. 插入記錄subscriber表,因爲sub_linkphone表必須使用新的用戶的ID。

  2. 將表中的記錄插入address表中,因爲在將記錄添加到sub_link之前必須存在addr_id

  3. subscriberaddress的最後記錄鏈接到sub_link表中。但是在這一步我有一個新問題:如何在PostgreSQL中有效地從步驟1)和步驟2)獲得sub_idaddr_id

  4. 然後,我需要插入一條記錄到phone表。至於第3步,我不知道如何有效地從以前的查詢中獲得sub_id

我讀了PostgreSQL裏的WITH塊,但是我不知道如何在我的情況下使用它。

UPDATE 我喜歡做建議:

-- 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); 

但我有一個錯誤:包含一個數據修改語句必須是在頂層 線路2條:爲T1 AS(INSERT INTO subscriber VALUES(DEFAULT,

回答

0

)你有這個想法,插入最頂層表中的數據,以便在插入對它們的引用之前就有它們的ID

在PostgreSQL可以使用INSERT/UPDATE ... RETURNING id結構。如果你不使用自動執行的一些ORM,這可能是有用的。

唯一這裏的事情是,在步驟2中,你可能要檢查,如果該地址已經存在插入前:

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

您可以使用帶有一個returning子句塊做這一切在一個查詢。請參閱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)) 

注意插入單行到每個表時,這種簡單的形式纔有效。

這有點偏離了你的問題的主題,但我建議你也考慮在電話表外鍵(使用REFERENCES)中創建sub_id和cat_id列。

+0

Postgres允許在WITH塊中執行兩個排序插入嗎?像這樣:INSERT INTO sub_link VALUES((SELECT sub_id FROM t1),(SELECT addr_id FROM t2)),INSERT INTO phone VALUES(DEFAULT,「1111111」,(SELECT sub_id FROM t1),...' – memset

+0

當然,只需將除最後一個INSERT之外的所有內容都放入它自己的WITH塊中,每個WITH塊都可以引用之前出現的別名,例如'... t3 AS(INSERT INTO sub_link VALUES((SELECT ... FROM t1),... ))INSERT INTO phone ...' – ASL

+0

更新的原始帖子。查詢變得非常複雜。使用嵌套的WITH'塊,我得到一個錯誤'WITH子句包含一個數據修改語句必須在頂部' – memset

相關問題