2016-04-30 77 views
1

我目前正在經歷試圖瞭解函數和觸發器的成長之痛。我試圖從我正在閱讀的書中解決問題,但我不知道如何做某些部分。觸發器和函數的麻煩

使用該表

create table movies (
    id  integer primary key, 
    title varchar(255) not null, 
    year integer 
); 

insert into movies values (1, 'The Croods', 2013); 
insert into movies values (2, 'Now You See Me', 2013); 
insert into movies values (3, 'Argo', 2012); 
insert into movies values (4, 'Jurassic World', 2015); 

create table discs (
    id   integer primary key, 
    movie_id integer not null references movies(id), 
    type_id  integer references disc_types(id), 
    price  decimal(10,2), 
    available boolean 
); 

insert into discs values (1, 1, 1, 1.59, 't'); 
insert into discs values (2, 1, 1, 1.59, 'f'); 
insert into discs values (3, 1, 2, 2.99, 'f'); 
insert into discs values (4, 2, 1, 1.29, 't'); 
insert into discs values (5, 2, 1, 1.29, 't'); 
insert into discs values (6, 2, 2, 2.99, 't'); 
insert into discs values (7, 3, 2, 2.59, 't'); 
insert into discs values (8, 3, 2, 2.59, 't'); 

create table customers (
    id  integer primary key, 
    name varchar(255), 
    email varchar(255) 
); 

insert into customers values (1, 'John', '[email protected]'); 
insert into customers values (2, 'Jane', '[email protected]'); 

create table rentals (
    id    integer primary key, 
    customer_id  integer not null references customers(id), 
    disc_id   integer not null references discs(id), 
    date_rented  date, 
    date_returned date 
); 

insert into rentals values (1, 1, 7, '2013-10-01', '2013-10-03'); 
insert into rentals values (2, 2, 5, '2013-10-05', '2013-10-06'); 
insert into rentals values (3, 2, 2, '2013-11-02', null); 
insert into rentals values (4, 2, 3, '2013-11-02', null); 

create table ratings (
    customer_id integer not null references customers(id), 
    movie_id integer not null references movies(id), 
    rating  integer, 
    primary key (customer_id, movie_id) 
); 

insert into ratings values (1, 1, 1); 
insert into ratings values (1, 2, 4); 
insert into ratings values (1, 3, 5); 
insert into ratings values (2, 1, 4); 

我的邏輯是,我本來是要被插入的收視率表的新值或更新,並使用它們來比較最新的租金錶,看是否該客戶已經租用了該電影,如果他們這樣做了,那麼他們可以輸入評級。但我不能在這個大聲笑中轉移那個邏輯。除非有更簡單的方法來做到這一點。

回答

0

函數內部的循環使事情變得複雜一點,讓我們看看我們是否可以擺脫它。您的評分表有參考客戶和電影,因此我們需要加入。

SELECT COUNT(*) INTO rented FROM rentals WHERE disc_id IN 
    (SELECT id from discs INNER JOIN 
    rentals ON disc_id = discs.id where movie_id = new.movie_id) 
    AND customer_id = new.customer_id 

對此,應該使存儲過程的邏輯更容易。我現在離開你去完成它,因爲畢竟這是一個學習練習。

您需要這種聯接,因爲它比循環更高效更簡單。該收視表具有對movie_id的引用,但租賃表僅具有disc_id,因此要查明用戶是否租用了特定電影,則需要通過光盤表將其加入。

您將需要更改返回值。裁判:http://www.postgresql.org/docs/9.2/static/plpgsql-trigger.html

行級觸發器之前觸發可以返回null信號觸發 經理跳過操作的休息此行(即 隨後的觸發器不會被觸發,而INSERT/UPDATE /對於這一行DELETE不會發生 )。如果返回一個非空值,則與該行價值

的 操作進行,並且也注意到,你不這樣做你的觸發功能內的INSERT。您只需返回一個非null值,即可繼續插入。

+0

你甚至不需要一個數,你可以使用'EXISTS(SELECT * FROM出租r,其中r.uid = new.uid和r.movi​​e_id = new.movi​​e)'在函數中。 (第二個想法,這甚至可能是一個FK的約束?) – wildplasser

+0

@ e4c5即時瞭解如何計數()如何幫助大聲笑 – henryzo

+0

好吧,所以這個函數計數時,新的信息匹配舊的信息權利?所以如果它匹配了1,所以如果租用> 0,那麼id在收視率中創建一個新的記錄?或者我想念這個大聲笑 – henryzo

0

這是EXISTS()版本。 (順便說一句:電影的定義缺失)

CREATE OR REPLACE FUNCTION rate_only_rented() 
RETURNS TRIGGER AS $func$ 
BEGIN 
IF (NOT EXISTS (
     SELECT * 
     FROM rentals r 
     JOIN discs d ON r.disc_id = d.id 
     WHERE d.movie_id = NEW.movie_id 
     AND r.customer_id = NEW.customer_id 
     )) THEN 
     RAISE EXCEPTION 'you(%) have not rented this movie(%) before' 
          , NEW.customer_id    ,NEW.movie_id; 
     RETURN NULL; 
ELSE 
     RETURN NEW; 
END IF; 
END; 
$func$ language plpgsql; 

和觸發:

CREATE TRIGGER rate_only_rented 
AFTER INSERT OR UPDATE 
ON ratings 
FOR EACH ROW 
EXECUTE PROCEDURE rate_only_rented() 
     ; 
+0

我對此進行了測試,看到了不同的方式,但是當我運行它時,無論somone是否租用了電影,它都會添加評級記錄。 – henryzo

+0

適用於此。礦是約束/拒絕觸發器。你的是一個「做而不是」的觸發器。 (我刪除了'insert into rating values(new.customer_id,new.movi​​e_id,new.rating);',因爲這是導致觸發器觸發的實際事件。 – wildplasser

+0

哦,我將觸發器定義更改爲'更新或插入後' – wildplasser