使用现有数据(来自 SQL Server)填充表(Firebird)后设置自动增量

问题描述 投票:0回答:1

我在 SQL Server 中有一个表。它的PK、ID是INT类型并且自动递增。我的任务是在 Firebird 数据库(版本 4.0.4)中获取此表。备注:我们有一个使用此数据库的网站,其中页面有大量对这些 ID 的引用,因此应保持原样。

我使用 .NET 6 (C#) 中的简单控制台程序来使用 ADO.NET 提供程序选择和插入数据。我的问题是,我是否应该首先将数据导入Firebird数据库,然后添加一个生成器作为该表的自动增量,考虑到生成器应该使用现有数据的PK最大值作为其起始值。据我了解,至少有两件事需要关心:

  1. 如果我先创建自增并插入数据(选择没有ID列),这些ID将从1开始。
  2. 我不确定该生成器从默认 0 值开始时的操作结果是什么。假设有 ID 2、4、5、8。在下一次插入时,它会创建 1 作为 ID。而第二次的结果又会如何呢? ++1 给出 2 已经在使用中,所以我们陷入困境。

我的方法正确吗?如果我错了请纠正我。

sql firebird auto-increment firebird-4.0
1个回答
0
投票

有多种方法可以解决这个问题。从 Firebird 3.0 开始,Firebird 拥有“真正的”身份列,这意味着您不必自己摆弄序列和触发器。缺点是无法将标识列添加到已有行的表中,并且无法将现有列转换为标识列。

鉴于您使用的是 Firebird 4.0,我建议您执行以下操作:

  1. 创建带有

    GENERATED ALWAYS AS IDENTITY
    列的表格。您也可以使用
    GENERATED BY DEFAULT AS IDENTITY
    ,但恕我直言,只有当您希望能够覆盖一般身份时,您才应该这样做:

    create table YOUR_TABLE (
      ID integer generated always as identity constraint PK_YOUR_TABLE primary key,
      -- your other columns
    );
    
  2. 如果您在上一步中使用了

    GENERATED ALWAYS
    ,请在 OVERRIDING SYSTEM VALUE
     语句中使用 
    INSERT
    。这样您就可以将显式值插入到generatealways标识列中。

    insert into YOUR_TABLE (ID, /* other columns */) overriding system value
      values (2, ...);
    

    如果您使用

    GENERATED BY DEFAULT
    ,则不需要`OVERRIDING子句(允许插入指定标识列值是默认生成的默认行为)。

  3. 插入所有行后,将标识列的下一个值更改为当前最大值+1(不是当前最大值!)。

    • 首先获取最大+1值:

      select 1 + max(ID) as NEXT_VALUE from YOUR_TABLE;
      

      确保在没有其他事务在此表中插入记录的情况下执行此操作。

    • 使用

      ALTER TABLE .. RESTART WITH ...
      中获得的值,假设
      NEXT_VALUE
      是1923年:

      alter table YOUR_TABLE alter column ID restart with 1923;
      
    • 或者,虽然正式不支持,但您可以使用 PSQL 代码将其作为一条语句运行:

      set term #;
      execute block
      as
        declare NEXT_VALUE integer;
      begin
        select 1 + max(ID) from YOUR_TABLE into NEXT_VALUE;
        execute statement 'alter table YOUR_TABLE alter column ID restart with ' || NEXT_VALUE;
      end#
      set term ;#
      

      注意:仅在交互式执行时才需要使用

      SET TERM
      ,例如使用 ISQL 时。 Firebird本身不支持该命令。例如,如果您从 C# 执行此操作,则只需执行
      execute block ... end
      (无需
      #
      !)。

  4. 从现在开始,在不指定

    ID
    列的情况下将记录插入到此表中(如果这样做,并使用 generatealways,除非指定了
    OVERRIDING SYSTEM VALUE
    ,否则将收到错误)。

如果您坚持使用序列(又名生成器),您可以执行以下操作:

  1. 创建具有普通整数列的表:

    create table YOUR_TABLE_2 (
      ID integer constraint PK_YOUR_TABLE_2 primary key,
      -- your other columns
    );
    
  2. 插入行:

    insert into YOUR_TABLE_2 (ID, /* other columns*/) values (2, ...);
    
  3. 插入行后,定义顺序并自动递增触发:

    • 首先获取下一个值:

      select 1 + max(ID) as NEXT_VALUE from YOUR_TABLE_2;
      
    • 然后创建序列和触发器(假设

      NEXT_VALUE
      是 1923):

      create sequence SEQ_YOUR_TABLE_2_ID start with 1923;
      set term #;
      create trigger GEN_ID_YOUR_TABLE_2 before insert on YOUR_TABLE_2
      as
      begin
        NEW.ID = next value for SEQ_YOUR_TABLE_2_ID;
      end#
      set term ;#
      

      注意:该触发器将无条件生成一个ID。您可能需要考虑在

      NEW.ID
      不为 null 时引发异常,或者仅在
      NEW ID
      为 null 时生成 ID。请参阅我的答案了解有条件的替代方案。

      虽然您可以使用 PSQL 技巧动态设置序列值,但我建议首先创建序列(省略

      START WITH
      子句),提交事务,然后使用
      EXECUTE BLOCK
      ALTER SEQUENCE ... RESTART WITH ...
      如果你想走那条路。

© www.soinside.com 2019 - 2024. All rights reserved.