簡體   English   中英

在PostgreSQL視圖上INSERT或UPDATE

[英]INSERT or UPDATE on PostgreSQL views

我從PostgreSQL視圖開始,因為它們對我的用例很有用,並且會提供比函數更好的性能。

(這不相關,但我在Heroku Postgres上使用Django 1.7 - 以防萬一)。

我已經創建了一個視圖,可以查詢它。 我想在視圖周圍寫一個Django包裝器,所以我可以像對待表一樣對待它,並相應地查詢和寫入它。 我一直在審查有關INSERTUPDATEPostgres文檔的觀點,但說實話,我發現他們的文檔很難閱讀,我幾乎無法解析他們所說的內容。

假設我有以下觀點:

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;

如何正確創建規則?

由於雙連接,最好使用觸發器過程。 要更新行業表,首先需要使用外鍵列表 - 公司 - 行業查找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;

注意:觸發程序是返回TRIGGER的正常程序。 根據觸發器的操作,該過程必須返回NEW或OLD(在本例中為NEW)。

並使用INSTEAD OF UPDATE子句觸發:

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

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

正如文檔所述 ,對於您希望在視圖上允許的每個操作, 必須有一個無條件的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規則。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM