Nic*_*der 5 postgresql auto-increment
我有一张桌子showtime和一张桌子ticket。
CREATE TABLE showtime (
showtime_id SERIAL PRIMARY KEY,
theatre_id INT REFERENCES theatre(theatre_id),
showroom_id INT REFERENCES showroom(showroom_id),
movie_id INT REFERENCES movie(movie_id),
start_time TIME,
end_time TIME,
show_date DATE
);
CREATE TABLE ticket (
showtime_id INT REFERENCES showtime(showtime_id),
seat_number SERIAL UNIQUE,
price NUMERIC(1000, 2) NOT NULL,
time_bought TIME,
date_bought DATE,
wasUsed BOOLEAN,
PRIMARY KEY (showtime_id, seat_number)
);
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,每一行都有showtime一个唯一的showtime_id. 我想要发生的是,当ticket添加新的时,seat_number应该从与以下内容相关的最后一个值自动递增showtime_id:
ticket
showtime_id | seat_number | instead_of |
1 | 1 | 1 |
1 | 2 | 2 |
1 | 3 | 3 |
1 | 4 | 4 |
2 | 1 | 5 |
2 | 2 | 6 |
3 | 1 | 7 |
4 | 1 | 8 |
Run Code Online (Sandbox Code Playgroud)
这在 PostgreSQL 中可能吗?
重新表述你的问题,这就是你想要的:每当你INSERT ticket有一个确定的数字时showtime_id,你想分配seat_number给下一个比ticket该数字已经存在的数字更高的数字showtime_id。那么已经存在的最高值是多少seat_number?简单的:
SELECT max(seat_number)
FROM ticket
WHERE showtime_id = ?; -- The ? being a parameter placeholder in languages like Java
Run Code Online (Sandbox Code Playgroud)
数据seat_number类型不应该是这样serial,因为不同的 s 会有重复的座位号showtimes_id。让它变得简单integer。
在一个INSERT声明中:
INSERT INTO ticket VALUES
(45,
(SELECT max(seat_number) FROM ticket WHERE showtime_id = 45) + 1,
...
);
Run Code Online (Sandbox Code Playgroud)
为了向您的用户或应用程序屏蔽此逻辑,您可以使用插入触发器来避免输入错误或非法(PK 违规)座位号:
CREATE FUNCTION assign_showtime_seat() RETURNS TRIGGER AS $$
BEGIN
SELECT max(seat_number) + 1 INTO NEW.seat_number
FROM ticket
WHERE showtime_id = NEW.showtime_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tr_assign_showtime_seat
BEFORE INSERT ON ticket
FOR EACH ROW EXECUTE PROCEDURE assign_showtime_seat();
Run Code Online (Sandbox Code Playgroud)
您很有可能会遇到并发问题,即showtime_id几乎同时输入同一票证的两张票证。第一个插入进入触发器并计算新的seat_number. 在INSERT完成之前,第二个票据插入进入触发器并计算相同的seat_number。然后,其中任一者管理实际INSERT并完成,然后第二个票证条目在插入时失败,并出现重复PRIMARY KEY违规。该文档提供了从此类并发问题中恢复的示例。
这是可能的,但对于并发访问来说要么非常不可靠,要么非常昂贵,因为您必须锁定整个表才能确定 - 锁定行是不够的,因为您无法锁定尚未输入的行。(好吧,对于一个单独的showtime表,引用表中的行锁会有所帮助,但这仅限于此......请参阅@zerkms 的评论)
如果可能的话,请坚持使用serial现在的列并使用VIEW或MATERIALIZED VIEW来得出您的数字:
CREATE MATERIALIZED VIEW v_ticket AS
SELECT *, row_number() OVER (PARTITION BY showtime_id
ORDER BY seat_number) AS seat_number_effective
FROM ticket;
Run Code Online (Sandbox Code Playgroud)
这为您提供了升序数字,每个 之间没有间隙showtime_id。
非常相似: