2016-04-30 61 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