【问题标题】:How to make a table share a sequence with another table in postgresql?如何使一个表与postgresql中的另一个表共享一个序列?
【发布时间】:2018-10-29 09:50:38
【问题描述】:

基本上,我有一个带有唯一城市特征 ID 的 table1,现在我有一个 table2 用于该国家/地区的特征。

我需要为国家表创建新的ID(这些需要与城市共享相同的序列,以便在交叉引用表时ID匹配)

如何使 table2 在该城市中具有与 table1 相同的 id,然后为其他地方的功能设置新的 id?本质上共享序列

编辑:表已经创建,我如何更新 table2

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    如果您手动创建一个序列并将其作为默认值分配给 ID 列,那么它就可以工作。但是要重用现有值,这意味着我们必须创建一个触发器来分配现有值或从共享序列中获取新值。

    create sequence baz;
    
    create table foo(id bigint default nextval('baz'), value text);
    
    create table bar(id bigint default nextval('baz'), value date);
    
    insert into foo (value) values ('Hello');
    insert into bar (value) values (now());
    insert into foo (value) values ('World');
    insert into bar (value) values (now());
    
    select 'foo', id, value::text from foo 
    union all
    select 'bar', id, value::text from bar
    

    结果是:

    foo 1   Hello
    bar 2   2018-10-29
    foo 3   World
    bar 4   2018-10-29
    

    作为奖励:

    drop sequence baz

    ERROR: cannot drop sequence baz because other objects depend on it
      Detail: 
        default for table foo column id depends on sequence baz
        default for table bar column id depends on sequence baz
      Hint: Use DROP ... CASCADE to drop the dependent objects too.
    

    编辑:如果我们可以进行后期处理,那么这种方法可以用于为缺少的 ID 列分配值:

    update bar
    SET id = coalesce((select id from foo where bar.city_name = foo.city_name),nextval('baz'))
    WHERE id is null
    

    【讨论】:

    • 不完全是我需要的,但我想你指出了正确的答案。我目前正在运行 update table2 set id = (select nextval('table1_seq1')) where id is null
    • 怎么样:更新 bar SET id = coalesce((select id from foo where bar.value::text = foo.value),nextval('baz')) WHERE id is null
    • table1 中的 id 已经填写完毕,所以不需要合并查询,谢谢。完成后会报告:)
    • Ermmm 所以在 1100 分钟后.....我的查询更新 table2 set id = (select nextval('table1_seq1')) where id is null 它只是把每一行都变成了 id 12548435
    • 因为 select nextval 仅在我估计一次时才被评估。你应该使用这个:Update table2 set id = nextval('table1_seq1') where id is null
    【解决方案2】:

    如果你的表已经创建,你必须创建一个序列

    create sequence seq_city_country;
    

    然后使用以下代码将序列添加到您的 id 中

    ALTER TABLE city ALTER COLUMN id_city SET DEFAULT nextval('seq_city_country');
    ALTER TABLE country ALTER COLUMN id_country SET DEFAULT nextval('seq_city_country');
    

    如果您的序列已经由 (sequence_c) 为表 city 创建,您可以使用

      ALTER TABLE country ALTER COLUMN id_country SET DEFAULT nextval('sequence_c');
    

    【讨论】:

      【解决方案3】:

      这听起来不像是非常好的(甚至可能的)数据库设计。相反,我建议创建一个连接表,将城市与各自的国家联系起来。因此,您的三个表可能如下所示:

      city (PK id, name, ...)
      country (PK id, name, ...)
      country_city (city_id, country_id)  PK (city_id -> city(id), country_id -> country(id))
      

      通过这种设计,您无需担心citycountry 表中的自动递增序列。只需让 Postgres 分配这些值,然后使用正确的值维护联结表即可。

      【讨论】:

      • 我不明白你的第三张桌子的概念。我需要做的是让两个表中的相同行共享相同的 id(尤其是因为这些行已经在其他表中使用过),而 table2 中的新行需要具有不同的 id
      • @Luffydude 不幸的是,您完全错过了我回答的重点。您的城市和国家/地区表应该通过主键和外键关系关联,而不是通过行序列。
      • 抱歉,如果我不清楚,序列是table1的主键,我需要未使用的序列号作为table2的主键
      • 是的,这基本上就是我的答案的工作方式。 idcountry 表的两个 id 列将是自动递增序列。那么联结表的主键将是来自每个序列的值的组合。
      • 但是我会有第三张桌子,其中两张已经超过 200gb
      【解决方案4】:
      CREATE SEQUENCE shared_seq;
      
      CREATE TABLE a (
         col1 bigint  DEFAULT nextval('shared_seq'),
         ...
      );
      
      CREATE TABLE b (
         col1 bigint  DEFAULT nextval('shared_seq'),
         ...
      );
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-10
        • 2022-11-09
        • 2012-11-08
        • 1970-01-01
        • 2018-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多