我在 SQL Server 中有一个表。它的PK、ID是INT类型并且自动递增。我的任务是在 Firebird 数据库(版本 4.0.4)中获取此表。备注:我们有一个使用此数据库的网站,其中页面有大量对这些 ID 的引用,因此应保持原样。
我使用 .NET 6 (C#) 中的简单控制台程序来使用 ADO.NET 提供程序选择和插入数据。我的问题是,我是否应该首先将数据导入Firebird数据库,然后添加一个生成器作为该表的自动增量,考虑到生成器应该使用现有数据的PK最大值作为其起始值。据我了解,至少有两件事需要关心:
我的方法正确吗?如果我错了请纠正我。
有多种方法可以解决这个问题。从 Firebird 3.0 开始,Firebird 拥有“真正的”身份列,这意味着您不必自己摆弄序列和触发器。缺点是无法将标识列添加到已有行的表中,并且无法将现有列转换为标识列。
鉴于您使用的是 Firebird 4.0,我建议您执行以下操作:
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
);
如果您在上一步中使用了
GENERATED ALWAYS
,请在 OVERRIDING SYSTEM VALUE
语句中使用
INSERT
。这样您就可以将显式值插入到generatealways标识列中。
insert into YOUR_TABLE (ID, /* other columns */) overriding system value
values (2, ...);
如果您使用
GENERATED BY DEFAULT
,则不需要`OVERRIDING子句(允许插入指定标识列值是默认生成的默认行为)。
插入所有行后,将标识列的下一个值更改为当前最大值+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
(无需 #
!)。
从现在开始,在不指定
ID
列的情况下将记录插入到此表中(如果这样做,并使用 generatealways,除非指定了 OVERRIDING SYSTEM VALUE
,否则将收到错误)。
如果您坚持使用序列(又名生成器),您可以执行以下操作:
创建具有普通整数列的表:
create table YOUR_TABLE_2 (
ID integer constraint PK_YOUR_TABLE_2 primary key,
-- your other columns
);
插入行:
insert into YOUR_TABLE_2 (ID, /* other columns*/) values (2, ...);
插入行后,定义顺序并自动递增触发:
首先获取下一个值:
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 ...
如果你想走那条路。