2015-07-20 94 views
3

我開始使用PostgreSQL視圖,因爲它們對我的用例很有用,並且會提供比函數更好的性能。 (這不相關,但我在Heroku Postgres —上使用Django 1.7以防萬一)。PostgreSQL視圖的INSERT或UPDATE

我已經創建了一個視圖,可以很好地查詢它。我想在視圖周圍編寫一個Django包裝器,以便我可以像處理表一樣處理它,並相應地查詢並寫入它。我一直在評論 Postgres docs on INSERT and UPDATE for views,但說實話,我發現他們的文檔很難閱讀,我幾乎無法解析他們在說什麼。

比方說,我有以下看法:

CREATE OR REPLACE VIEW links AS 
    SELECT 
    listing.id              AS listing_id, 
    CONCAT('/i-', industry.slug, '-j-', listing.slug, '/') AS link, 
    'https://www.example.com' || CONCAT(industry.slug, '-SEP-', listing.slug, '/') AS full_link, 
    listing.slug AS listing_slug, 
    industry.slug AS industry_slug 
    FROM listing 
    INNER JOIN company ON company.id = listing.company_id 
    INNER JOIN industry ON industry.id = company.industry_id 

在這裏,我使用industry.sluglisting.slug建立聯繫。我希望能夠更新從該視圖這兩個領域,因爲這樣的:

UPDATE links 
SET listing_slug = 'my-new-slug' 
WHERE listing_id = 5; 

如何創建規則正確做到這一點?

+0

因爲它不是一個的simpy更新視圖(已連接),你需要寫一個'DO INSTEAD'規則或觸發。規則是複雜的,很難得到正確的,所以我會使用觸發器。 –

回答

1

由於雙連接,最好使用觸發器程序。要更新行業表,您首先需要使用外鍵上市公司行業來查找industry.id。 的過程可能看起來像這樣:

CREATE OR REPLACE FUNCTION update_listing_and_industry() RETURNS TRIGGER AS 
    $$ 
    DECLARE _company_id int; _industry_id int; 
    BEGIN 
    _company_id = (SELECT company_id FROM listing WHERE id = OLD.listing_id); 
    _industry_id = (SELECT industry_id FROM company WHERE id = _company_id); 

    UPDATE listing SET slug = NEW.listing_slug WHERE id = OLD.listing_id; 
    UPDATE industry SET slug = NEW.industry_slug WHERE id = _industry_id; 
    RETURN NEW; 
    END; 
    $$ 
LANGUAGE plpgsql; 

注:觸發器過程是返回一個觸發一個正常的程序。根據觸發器的作用,程序必須返回NEW或OLD(在本例中爲NEW)。

而且隨着INSTEAD OF UPDATE條款觸發:

CREATE trigger update_view INSTEAD OF UPDATE ON links 
FOR EACH ROW EXECUTE PROCEDURE update_listing_and_industry(); 
0

您視圖中唯一可更新的列是listing_slug。 更新其他列是不可能或毫無意義的(例如,更新industry_slug是沒有意義的,因爲視圖中沒有industry的主鍵)。 在這種情況下,您應該使用一個有條件的規則,它排除了更新其他列的能力。

因爲它在the documentation描述,有必須是要允許在視圖中的每個動作無條件INSTEAD規則。因此,你應該創建用於更新和條件ALSO規則虛設INSTEAD規則:

CREATE RULE update_links_default 
AS ON UPDATE TO links DO INSTEAD NOTHING; 

CREATE RULE update_links_listing 
AS ON UPDATE TO links 
WHERE NEW.listing_slug <> OLD.listing_slug 
DO ALSO 
    UPDATE listing 
    SET slug = NEW.listing_slug 
    WHERE id = OLD.listing_id; 

如果您將添加列industry.id as industry_id到視圖,您可以定義適當的規則表industry

CREATE RULE update_links_industry 
AS ON UPDATE TO links 
WHERE NEW.industry_slug <> OLD.industry_slug 
DO ALSO 
    UPDATE industry 
    SET slug = NEW.industry_slug 
    WHERE id = OLD.industry_id; 

通常,您需要一個ALSO規則。