2011-12-13 37 views
5

我目前正在修改Firebird 1.5版数据库。更新生成器值问题

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

/* 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从每一个表中的一个命令,但事实并非如此。

+0

你在使用什么组件? – rstrelba

+0

@rstrelba interbase – ComputerSaysNo

+0

我对delphi组件感兴趣。 TIBDatabase? TIBQuery? TIBDataSet? – rstrelba

回答

6

声明

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

混合DDL(SET GENERATOR)和DML(SELECT),AFAIK这不是普遍支持和Firebird不支持它肯定。

如果你可以升级到火鸟的最新版本,那么你可以使用EXECUTE BLOCK和/或EXECUTE STATEMENT做这一切“在一个声明”和服务器端,但与火鸟1.5你不得不接受的很长的路要走(一个语句来获取当前最大值,然后另一个更新生成器)。

+0

+1谢谢你,我不能升级,因为代码基础很大,测试所有功能的时间是有限的,因此升级是不可能的。我希望有一个更优雅的解决方案): – ComputerSaysNo

+0

我认为我给了这个问题足够的时间,你的答案更接近我的问题,不幸的是我必须用解决问题的“更长的路”去解决问题,这意味着多个查询...,谢谢你的回答(: – ComputerSaysNo

4

您可以创建一个存储过程,并从德尔福调用它:

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^ 

看起来execute statementsupported by Firebird 1.5了。 在Firebird 2.0及更高版本中,您也可以将代码包装在execute block中,并避免创建存储过程。

+0

+1谢谢你TOndrej,你说得对,GEN_TABLENAME是约定,但我更喜欢更简单的解决方案 – ComputerSaysNo

2

通过下面的技巧你可以到发电机值设置为同一个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以及更新的版本中起作用。

+0

如果你知道生成器是0,这更简单:'SELECT GEN_ID(GEN_TABLENAME,(SELECT MAX(ID)FROM TABLENAME))FROM RDB $ DATABASE;' – yonojoy