2008-10-02 21 views
1

的視圖更新在一個多到一的關係兩個表我有兩個表:foosbars,並且在它們之間存在一個多到一的關係:每個foo可以有許多bars。我也有一個觀點foobars,加入這兩個表(它的查詢就像select foo.*, bar.id from foos, bars where bar.foo_id=foo.id)。通過PostgreSQL中

編輯:如果您說foo s和bar s之間存在多對多關係,那麼您就不會錯。然而,bar僅僅是一個標籤(實際上它是一個尺寸),並且僅由它的名字組成。表bars與鏈接表具有相同的作用。

我有一個插入到foobars的規則,以便將「foo」部分作爲新行插入到foos中,並且包含由逗號分隔的幾個條形ID的「bar」部分被拆分,並且對於每個這樣的部分,它與適當的foo之間的鏈接被創建(我使用一個過程來做到這一點)。

這對插入很有用。但是,當涉及到更新整個事情時,我有一個問題。該規則的foo部分很簡單。但是,我不知道如何處理多個bar的部分。當我在規則中嘗試執行類似DELETE FROM bars WHERE foo_id=new.foo_id的操作時,我將從表bars中刪除所有內容。

我在做什麼錯?有沒有辦法達到我需要的?最後,我認爲整個事情是合理的嗎?

(我做的這個觀點過於複雜的事情,因爲我得到的數據是在「foo及其所有bar的」的形式,但用戶必須看到的只是foobars

回答

0

我不認爲new.foo_id在刪除的上下文中是正確的。

不應該從檔案裏刪除哪裏foo_id = old.foo_id?

2

Rysiek,如果我理解正確的話,表中的文本列在foos表中被解析以提取指向bars表的外鍵。這種建立關係的方法在某些情況下可能是合理的,但幾乎所有的數據庫編程指南都會阻止這樣做。爲什麼不在bars中使用標準外鍵,它會指向foos中的foo?除非要求將酒吧分配給多個富人。如果是這樣,這將您的關係標識爲多對多而非一對多。在任何一種情況下,使用基於標準外鍵的解決方案似乎對數據庫來說都更加自然。

實例DB模式的一個一對多的關係:

CREATE TABLE foos (
    id SERIAL PRIMARY KEY, 
    .... 
); 
CREATE TABLE bars (
    id SERIAL PRIMARY KEY, 
    foo_id INT REFERENCES bars (id) ON DELETE CASCADE, 
    ... 
); 

與同爲許多一對多的關係:

CREATE TABLE foos (
    id SERIAL PRIMARY KEY, 
    .... 
); 
CREATE TABLE bars (
    id SERIAL PRIMARY KEY, 
    ... 
); 
CREATE TABLE foostobars (
    foo_id INT REFERENCES foos (id) ON DELETE CASCADE, 
    bar_id INT REFERENCES bars (id) ON DELETE CASCADE 
); 

我也建議使用INNER JOIN代替表乘法(SELECT FROM foos,bars)。

CREATE VIEW foobars AS 
SELECT 
    foos.id AS foo_id, foos.something, 
    bars.id AS bar_id, bars.somethingelse 
FROM foos 
INNER JOIN bars ON bars.foo_id = foo.id; 

同樣對於許多到許多內部聯接

CREATE VIEW foobars AS 
SELECT 
    foos.id AS foo_id, foos.something, 
    bars.id AS bar_id, bars.somethingelse 
FROM foos 
INNER JOIN foostobars AS ftb ON ftb.foo_id = foo.id 
INNER JOIN bars ON bars.id = ftb.bar_id; 
+0

不應該將顯式和隱式內部聯接精確地針對相同的查詢計劃進行優化嗎?至少在Postgres中會發生這種情況。我編輯了這篇文章,解釋爲什麼我不使用鏈接表。 – 2008-10-02 10:30:11

0

這就是我實際上已經處理了它:當我違反唯一約束,而不是更新我只是刪除foo並讓級聯照顧bars。然後,我只是嘗試再次插入。我必須使用多個SQL語句來完成它,但它似乎工作。

0

刪除問題是,您正在刪除不基於要從中刪除的表的謂詞。您需要根據連接謂詞進行刪除。這看起來是行:

delete b 
    from foo f 
    join foobar fb 
    on f.FooID = fb.FooID 
    join bar b 
    on b.BarId = fb.BarID 
where f.FooID = 123 

這可以讓你的Jave Foo的表,酒吧的的表和記錄什麼酒吧的foo的具有連接表。您不需要編寫列表並將它們分開。這是一件壞事,因爲查詢優化器不能使用索引來確定相關的記錄 - 實際上這違反了1NF「不重複的組」的規則..正確的模式看起來是這樣的:

Create table Foo (
    FooID int 
    ,[Other Foo attributes] 
) 

Create table Bar (
    BarID int 
    ,[Other Bar attributes] 
) 

Create table FooBar (
    FooID int 
    ,BarID int 
) 

通過適當的索引,M:M關係可以存儲在FooBar中,並且DBMS可以在其本機數據結構中有效地存儲和操作它。