Delphi:如何以编程方式创建 Firebird 数据库

Posted

技术标签:

【中文标题】Delphi:如何以编程方式创建 Firebird 数据库【英文标题】:Delphi: how to create Firebird database programmatically 【发布时间】:2011-02-15 16:13:25 【问题描述】:

我正在使用 D2K9、Zeos 7Alpha 和 Firebird 2.1

在添加 autoinc 字段之前,我已经完成了这项工作。虽然我不确定我做的是否 100% 正确。我不知道使用触发器、生成器等执行 SQL 代码的顺序。我尝试了几种组合,我猜我做错了什么,而不仅仅是因为这不起作用。

当前演示: http://uploading.com/files/bd64d8m9/createdb.zip/

当前错误:

It's getting an error here:

SQL Error:  Dynamic SQL Error SQL error code = -104 Token unknown - line 2, column 1 SET.
Error Code: -104. Invalid token The SQL:
 CREATE GENERATOR GEN_EMAIL_ACCOUNTS_ID;

将 GENERATOR GEN_EMAIL_ACCOUNTS_ID 设置为 1;

来自 IBExpert 的 SQL 文件:

/******************************************************************************/
/*                 Generated by IBExpert 5/4/2010 3:59:48 PM                  */
/******************************************************************************/

/******************************************************************************/
/*        Following SET SQL DIALECT is just for the Database Comparer         */
/******************************************************************************/
SET SQL DIALECT 3;



/******************************************************************************/
/*                                   Tables                                   */
/******************************************************************************/


CREATE GENERATOR GEN_EMAIL_ACCOUNTS_ID;

CREATE TABLE EMAIL_ACCOUNTS (
    ID           INTEGER NOT NULL,
    FNAME        VARCHAR(35),
    LNAME        VARCHAR(35),
    ADDRESS      VARCHAR(100),
    CITY         VARCHAR(35),
    STATE        VARCHAR(35),
    ZIPCODE      VARCHAR(20),
    BDAY         DATE,
    PHONE        VARCHAR(20),
    UNAME        VARCHAR(255),
    PASS         VARCHAR(20),
    EMAIL        VARCHAR(255),
    CREATEDDATE  DATE,
    "ACTIVE"     BOOLEAN DEFAULT 0 NOT NULL /* BOOLEAN = SMALLINT CHECK (value is null or value in (0, 1)) */,
    BANNED       BOOLEAN DEFAULT 0 NOT NULL /* BOOLEAN = SMALLINT CHECK (value is null or value in (0, 1)) */,
    "PUBLIC"     BOOLEAN DEFAULT 0 NOT NULL /* BOOLEAN = SMALLINT CHECK (value is null or value in (0, 1)) */,
    NOTES        BLOB SUB_TYPE 0 SEGMENT SIZE 1024
);




/******************************************************************************/
/*                                Primary Keys                                */
/******************************************************************************/

ALTER TABLE EMAIL_ACCOUNTS ADD PRIMARY KEY (ID);


/******************************************************************************/
/*                                  Triggers                                  */
/******************************************************************************/


SET TERM ^ ;



/******************************************************************************/
/*                            Triggers for tables                             */
/******************************************************************************/



/* Trigger: EMAIL_ACCOUNTS_BI */
CREATE OR ALTER TRIGGER EMAIL_ACCOUNTS_BI FOR EMAIL_ACCOUNTS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
  IF (NEW.ID IS NULL) THEN
    NEW.ID = GEN_ID(GEN_EMAIL_ACCOUNTS_ID,1);
END
^


SET TERM ; ^



/******************************************************************************/
/*                                 Privileges                                 */
/******************************************************************************/

触发器:

/******************************************************************************/
/*        Following SET SQL DIALECT is just for the Database Comparer         */
/******************************************************************************/
SET SQL DIALECT 3;

CREATE GENERATOR GEN_EMAIL_ACCOUNTS_ID;

SET TERM ^ ;



CREATE OR ALTER TRIGGER EMAIL_ACCOUNTS_BI FOR EMAIL_ACCOUNTS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
  IF (NEW.ID IS NULL) THEN
    NEW.ID = GEN_ID(GEN_EMAIL_ACCOUNTS_ID,1);
END
^


SET TERM ; ^

发电机:

CREATE SEQUENCE GEN_EMAIL_ACCOUNTS_ID;
ALTER SEQUENCE GEN_EMAIL_ACCOUNTS_ID RESTART WITH 2;

/* Old syntax is:
CREATE GENERATOR GEN_EMAIL_ACCOUNTS_ID;
SET GENERATOR GEN_EMAIL_ACCOUNTS_ID TO 2;
*/

我的代码:下面的 cmets 中的演示。

【问题讨论】:

如果您提供这样的文字墙,它会阻止人们。不要使用codepre 标签,而是使用编辑器中的代码格式化工具栏按钮,或者简单地将代码缩进4 个空格。此外,删除人们理解问题所不需要的所有内容,例如 IBExpert 脚本中的许多 cmets 和空行。 我没有显示代码格式化工具栏.. 但下次我会尝试将所有内容格式化得更好一些,尽管它在我的浏览器中显示得很好。 这里没有正确显示(Mac OS X 上的 Firefox)。你应该有格式化按钮,它是编辑控件上方工具栏上带有小“0”和“1”的那个,它有提示“代码示例......”。 这是我所拥有的 uploading.com/files/bd64d8m9/createdb.zip 的演示。它得到一个错误:SQL 错误:动态 SQL 错误 SQL 错误代码 = -104 令牌未知 - 第 2 行,第 1 列 SET。错误代码:-104。无效令牌 SQL: CREATE GENERATOR GEN_EMAIL_ACCOUNTS_ID;将 GENERATOR GEN_EMAIL_ACCOUNTS_ID 设置为 1;需要,JVCL,Zeos db(使用版本 7) 【参考方案1】:

通常您可以按任何顺序创建 Firebird 数据库对象,前提是它们不相互依赖。如果是这样,那么显然您需要在创建依赖对象之前创建依赖对象。

如果您有具有循环引用的对象,则首先创建一个空主体,创建另一个,然后使用ALTER TABLE 或相应的语句填充第一个的内容。 IBExpert、Database Workbench 或 FlameRobin 等工具会分析依赖关系,因此在它们编写的脚本中遵循创建顺序应该始终有效。

如果您的 IBExpert 创建的脚本有效,但您自己的代码以相同的顺序执行操作不起作用,那么原因可能在于 IBExpert 分别提交每个 DDL 语句(而您的代码没有)。你可以在你的代码中做同样的事情,你应该这样做。您的 autoinc 列涉及一个触发器,该触发器本身依赖于生成器,因此请确保在创建表和生成器之后提交,然后再创建触发器。

编辑:

您应该确保只使用能够执行此操作的数据库组件执行多个语句。我不认识 Zeos,但从 this knowledge base article 看来,TZQueryTZUpdateSQL 在一个执行调用中都支持多个语句。或者,您应该能够使用TZSQLProcessor 加载由 IBExpert 创建的完整脚本并执行它。

另一方面,TZConnection.ExecuteDirect() 方法可能不支持多条语句,在这种情况下,您将在第一条语句结束后出现语法错误。这个

CREATE GENERATOR GEN_EMAIL_ACCOUNTS_ID;
SET GENERATOR GEN_EMAIL_ACCOUNTS_ID TO 2;

是两个语句,您可能需要分别将每个语句传递给TZConnection.ExecuteDirect()

【讨论】:

您能告诉我分别执行每个 DDL 是什么意思吗?我以为我是分开做的。 @Brad:你分开做,但你可能也需要提交你的工作。您可以设置一些 Zeos 选项来自动提交 DDL,或者您需要显式提交事务。我没有使用 Zeos 的经验,但是像 Commit()CommitRetaining() 这样的东西应该可以在数据库对象或专用事务对象上使用。有关交易的更多信息,请参阅 firebirdfaq.org 上的文章。

以上是关于Delphi:如何以编程方式创建 Firebird 数据库的主要内容,如果未能解决你的问题,请参考以下文章

我可以以编程方式退出 Firebird 脚本吗

Firebird(如何使用 SQL 查找父类别)

使用 Delphi 应用程序的 Firebird 错误“未定义用户名和密码”

如何以编程方式控制我的电脑的音量?

使用 Delphi XE-8 和 FIREBIRD 本地数据库时出现“SELECT * FROM ....”异常

使用 Delphi XE-8 和 FIREBIRD 本地数据库时出现“SELECT * FROM ....”异常