6

我目前正在修改 Firebird v. 1.5 数据库。

数据库结构将被修改从使用 interbase 组件的 delphi 应用程序运行查询,我面临的问题是我需要运行很多查询,其中一些包括创建生成器和更新生成器值,问题是我需要在尽可能少的查询中实现这一点,但似乎(至少对我而言)这实际上是不可能的,我想要做的是以下几点:

 /* this command creates a generator to be used for table TABLENAME */
CREATE GENERATOR GEN_TABLENAME;

所以我创建了一个生成器,现在我需要将它的值设置为表 TABLENAME 中的当前最大 id,如下所示:

/* one would expect that the following command would work, well it doesn't */
SET GENERATOR GEN_TABLENAME TO (SELECT MAX(ID) FROM TABLENAME);

现在,是否有任何解决方法,或者我被迫:

  • 创建生成器
  • 获取最大id
  • 更新生成器值

并为每张桌子重复这个过程?

我也期待

SELECT
  SELECT MAX(ID) AS ID_TABLENAME_1 FROM TABLENAME_1,
  ...
  SELECT MAX(ID) AS ID_TABLENAME_N FROM TABLENAME_N

在一个命令中从每个表中获取最大 id 是一种解决方法,但事实并非如此。

4

3 回答 3

8

陈述

SET GENERATOR GEN_TABLENAME TO (SELECT MAX(ID) FROM TABLENAME);

混合 DDL ( SET GENERATOR) 和 DML ( SELECT),AFAIK 这通常不受支持,Firebird 肯定不支持它。

如果您可以升级到最新版本的 Firebird,那么您可以使用EXECUTE BLOCK和/或EXECUTE STATEMENT “在一个语句中”和服务器端完成所有操作,但是对于 Firebird 1.5,您必须适应很长的路要走(一个语句获取当前最大值,然后另一个更新生成器)。

于 2011-12-13T10:42:40.990 回答
5

通过以下技巧,您可以使用 Firebird 中的一条 SQL 语句将生成器值设置为表的最大 ID 值:

SELECT GEN_ID( GEN_TABLENAME, 
  (SELECT MAX(ID) FROM TABLENAME) - GEN_ID(GEN_TABLENAME, 0)) FROM RDB$DATABASE;

这行得通,因为GEN_ID( <GeneratorName>, <increment>)获取生成器值并将其递增<increment>. 这应该适用于 Firebird 1.5 以及较新的版本。

于 2016-05-03T12:43:10.330 回答
4

您可以创建一个存储过程并从 Delphi 调用它:

create procedure update_generators
as
  declare variable max_id integer;
  declare variable table_name char(31);
  declare variable generator_name char(31);
begin
  /* assuming generator naming convention GEN_XXX -> table name XXX */
  for select
    trim(g.rdb$generator_name),
    substring(trim(g.rdb$generator_name) from 5)
  from rdb$generators g
  where (coalesce(g.rdb$system_flag, 0) = 0)
  into
    :generator_name,
    :table_name
  do
  begin
    /* assuming that the field name is always ID */
    execute statement 'select max(id) from ' || :table_name into :max_id;
    execute statement 'set generator ' || :generator_name || ' to ' || :max_id;
  end
end^

看起来Firebird 1.5 已经支持execute statement了。在 Firebird 2.0 及更高版本中,您还可以将代码包装在 a 中并避免创建存储过程。execute block

于 2011-12-13T10:49:10.590 回答