【问题标题】:Dependent SERIAL column in PostgreSQLPostgreSQL 中的从属 SERIAL 列
【发布时间】:2015-08-10 05:17:13
【问题描述】:

我想在我的表中得到这个结果contacts

 |contact_id |  user_id         |  user_contact_id     |
 +-----------+------------------+----------------------+
 |  1        |  1               |          1           |
 +-----------+------------------+----------------------+
 |  2        |  1               |          2           |
 +-----------+------------------+----------------------+
 |  3        |  1               |          3           |
 +-----------+------------------+----------------------+
 |  4        |  2               |          1           |
 +-----------+------------------+----------------------+
 |  5        |  2               |          2           |
 +-----------+------------------+----------------------+
 |  6        |  2               |          3           |
 +-----------+------------------+----------------------+
 |  7        |  3               |          1           |
 +-----------+------------------+----------------------+

我将只插入user_id

INSERT INTO contacts (user_id) VALUES ($user_id);

contact_id 将自动递增,因为它是 serial。我希望user_contact_id 也由数据库本身自动填充,因此它在并发写入时是 100% 稳定的。

【问题讨论】:

  • user_contact_id的值是不是一直从1到3算?
  • 跟进上一个相关问题。 stackoverflow.com/questions/30469032/…
  • 由于并发问题,这并非微不足道。你需要非常精确。请澄清在您的问题中:您的 Postgres 版本? (user_id, user_contact_id) 必须是唯一的还是偶尔被骗的可以 - 可以通过 contact_id 来区分。 (会使它很多更简单。)如何处理由于DELETE 和/或UPDATE 而导致的user_contact_id 中的空白,或者它是仅INSERT?序列中的间隙可以吗?您知道在并发负载下,serial 列中会出现预期的空白,对吧?这个用例是 few 还是 many 用户?
  • @ErwinBrandstetter : 我使用的是 Postgres 9.4.1,骗子不是借口,我需要一个严格的阵容,因为我要结合 user_id 使用contact_user_id,所以它必须始终是唯一的
  • 我是否正确阅读了您的简短评论:您不会进一步澄清您的问题吗?

标签: sql postgresql concurrency auto-increment sql-insert


【解决方案1】:
INSERT INTO CONTACTS
    (user_id, user_contact_id)
VALUES
    ($user_id, (SELECT COALESCE(MAX(user_contact_id), 0) + 1 FROM CONTACTS WHERE user_id = $user_id))

【讨论】:

  • Michael - 这很酷,但是并发性如何,我将在有很多客户将记录插入数据库的情况下使用它
  • 如果有新用户,这也不起作用,因为 MAX 将返回 null 和 null+1 == null。
  • @SamiKuhmonen 这是真的,我同意,你有什么解决方法吗?
  • @CodeRows 为此可以使用COALESCE,使用COALESCE(MAX(user_contact_id), 0)+1
  • @CodeRows 您的并发问题是正确的。你不应该使用它——它很容易受到种族歧视。
【解决方案2】:

正如其他用户建议的那样,只有 sequence-s 或 serial 类型保证是并发安全的。

如果你真的需要让user_contact_id“重启”每个user_id,也许你可以使用以下视图:

create view contacts_v as
select
  contact_id,
  user_id,
  rank() over (partition by user_id order by contact_id) as user_contact_id
from contacts;

【讨论】:

    【解决方案3】:

    您应该使用序列作为user_contact_id 的默认值。这正是SERIAL 列类型正在做的事情。

    http://www.postgresql.org/docs/9.1/static/datatype-numeric.html http://www.postgresql.org/docs/9.4/static/sql-createsequence.html

    序列对于并发写入是安全的。

    CREATE TABLE contacts (
      contact_id      SERIAL PRIMARY KEY,
      user_id         INTEGER,
      user_contact_id SERIAL
    );
    
    INSERT INTO contacts (user_id) VALUES
      (1), (1), (1), (2), (2), (2), (3);
    

    结果如下:

    > SELECT * FROM contacts;
     contact_id | user_id | user_contact_id
    ------------+---------+-----------------
              1 |       1 |               1
              2 |       1 |               2
              3 |       1 |               3
              4 |       2 |               4
              5 |       2 |               5
              6 |       2 |               6
              7 |       3 |               7
    
    > \d contacts
                                        Table "public.contacts"
         Column      |  Type   |                             Modifiers
    -----------------+---------+--------------------------------------------------------------------
     contact_id      | integer | not null default nextval('contacts_contact_id_seq'::regclass)
     user_id         | integer |
     user_contact_id | integer | not null default nextval('contacts_user_contact_id_seq'::regclass)
    Indexes:
        "contacts_pkey" PRIMARY KEY, btree (contact_id)
    

    【讨论】:

    • 我对原始问题的理解是,OP 希望 user_contact_id 具有每个 user_id 独立增加的值。
    • 哦,我没注意到,抱歉,如果是这样,我就删除这个答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    • 2018-04-21
    • 2010-11-22
    • 1970-01-01
    • 2018-11-06
    • 2014-06-22
    • 2013-08-25
    相关资源
    最近更新 更多