基于另一个属性的自动增量属性

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 中可能吗?

Pat*_*ick 7

重新表述你的问题,这就是你想要的:每当你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违规。该文档提供了从此类并发问题中恢复的示例。


Erw*_*ter 5

这是可能的,但对于并发访问来说要么非常不可靠,要么非常昂贵,因为您必须锁定整个表才能确定 - 锁定行是不够的,因为您无法锁定尚未输入的行。(好吧,对于一个单独的showtime表,引用表中的行锁会有所帮助,但这仅限于此......请参阅@zerkms 的评论)

如果可能的话,请坚持使用serial现在的列并使用VIEWMATERIALIZED 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

非常相似: