【问题标题】:Delphi - Creating MySQL database at runtimeDelphi - 在运行时创建 MySQL 数据库
【发布时间】:2013-04-16 22:14:36
【问题描述】:

我有一个连接到 MySQL 数据库的 delphi 应用程序,但是,我想为我的最终用户创建一个简单的方法来实现 MySQL 数据库。我考虑在我的应用程序中创建一个按钮,用户可以按下该按钮来删除 scehma 的任何当前实例,并使用我的应用程序运行所需的正确表和列创建一个新模式。

我已经编写了创建新数据库的代码。如下:

CREATE SCHEMA IF NOT EXISTS fakeschema;   
USE fakeschema;  
CREATE TABLE table1  
(IDtable1 int(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,  
Line1 varchar(45),  
Line2 varchar(45));  

代码在 MySQL 中正常运行,但是在执行代码时收到 SQL 语法错误。我得到了:

'USE fakeschema; 附近的 SQL 语法错误; CREATE TABLE table1 (IDtable1 int(11) PRIMARY KEY NO'

我正在使用ADOConnection 链接到数据源。按下按钮后,我正在编写连接字符串。我正在使用ADOQuery 来执行 SQL 代码。

这是我用来连接数据库的代码的 sn-p:

ADOC.ConnectionString := 'PROVIDER = MSDASQL; DRIVER={MySQL ODBC 3.51 Driver};
SERVER=localhost; Data Source=faketest; DATABASE=fakeschema; USER ID=root;
PASSWORD=pass; OPTION=3;';
ADOC.DefaultDatabase := 'fakeschema';  
ADOC.Connected := True;  

我是否使用了错误的工具/方法?我是 MySQL 新手,目前正在学习 Delphi。

【问题讨论】:

  • “我收到一个 SQL 语法错误”而不发布您收到的具体错误消息是没有意义的。请edit您的问题并附上exact错误信息。谢谢。
  • @KenWhite 我已经进行了编辑。谢谢
  • @KenWhite 我明白你的意思。过去我遇到了很多麻烦,我需要做的就是编辑几个字符。但是,这里的情况似乎并非如此。我尝试删除 auto_inc 和 notnull,并尝试从 line1 部分开始列括号,以便完全删除 id 行......但运气不好。两者都提供完全相同的错误,只是显示了相应的代码行。
  • 您是否需要使用与 TAdoQuery 不同的组件?它可能一次只需要执行一条语句。我知道使用 Interbase/Firebird 样式,您需要使用 TIBScript 组件“一次”执行多个语句。但我不知道。只是猜测
  • 忽略我最后的评论。 documentation 并不清楚这里需要什么。我还在四处挖掘。 :-)

标签: mysql sql delphi runtime


【解决方案1】:

正如我的一个 cmets 中提到的,问题是试图在单个 TAdoQuery 组件中执行多个 individual SQL 语句。

在理想情况下,您将拥有一个组件,例如 MyDAC,它有一个脚本组件,您可以使用它来代替 TAdoQuery(MyDAC 也会给您带来其他好处,例如不必通过 ODBC 连接)。我不知道是否有任何免费的 MySQL 组件有脚本组件。

另一种方法是您可以创建一个脚本文件(例如 createFakeSchema.sql)并通过命令行执行它。例如:

createFakeSchema.sql:

CREATE SCHEMA IF NOT EXISTS fakeschema;   
USE fakeschema;  
CREATE TABLE table1  
(IDtable1 int(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,  
Line1 varchar(45),  
Line2 varchar(45));

和示例源代码:

procedure TfrmMain.DoExecuteScriptFile;
var
  cmd: string;
  KeepOpen: Boolean;
begin
  KeepOpen := True;

  // option to automatically close window once execution is done
  // for releasing you would not want it kept open, but handy for debugging
  if KeepOpen then
    cmd := '/k '
  else
    cmd := '/c ';

  cmd := cmd + Format(' mysql -uroot -proot -D%s < "%s"', ['FakeSchema', 'createFakeSchema.sql']);
  ShellExecute(handle,'open', 'cmd.exe', Pchar(cmd), nil, SW_SHOW );
end;

这样您就可以在外部某处创建脚本文件,自己通过 MySQL 对其进行测试,然后当您知道您的 脚本 正在运行时,您可以通过您的程序运行它。如果要在执行时隐藏命令窗口,请将 ShellExecute 中的 SW_SHOW 更改为 SW_HIDE。这样,您甚至根本不需要任何组件 - 只需在路径中访问 mysql.exe 或在 cmd 语句中包含完整路径。

这是在 MySQL 5.1 中完成的,所以希望适用于 3.5...

【讨论】:

  • 感谢您的帮助。我已经拆分查询并创建了一个单独的查询来创建数据库。我有一个简单地创建数据库fakeschema,然后我有一个单独的ADOQuery,它将SQL添加到CREATE table1,执行SQL,清除查询,然后为下一个表添加并执行SQL等。它工作美好的。我喜欢从文件中执行的想法,并且可以将其用于将来的参考。
【解决方案2】:

如果您查看 MySQL 3.x 的 documentation,并在 CREATE TABLE 上向下滚动页面,您将在其中一个评论帖子中看到一个看起来是正确语法的示例。它似乎更像这样(当然未经测试):

CREATE TABLE IF NOT EXISTS Table1 (
  IDtable1 int(11) NOT NULL AUTO_INCREMENT,  
  Line1 varchar(45),  
  Line2 varchar(45)
  PRIMARY KEY (IDTable1)
);

这是我在DevArticles找到的另一个例子

CREATE TABLE `articles` (
  `aID` int(4) NOT NULL auto_increment,
  `auth` varchar(100) NOT NULL default '',
  `title` varchar(100) NOT NULL default '',
  `article_body` text NOT NULL,
  `date_published` date NOT NULL default '0000-00-00',
  PRIMARY KEY  (`aID`)
) 

不过,您可能需要重新考虑您的策略。如果用户不小心点击了Reset Database 按钮并删除了他们的所有数据,这可能会给您带来一些问题(可能是合法问题,具体取决于您的居住地和所涉及的数据)。 :-)

最好考虑备份数据,然后对表执行TRUNCATE,如果出现问题,您可以从备份中恢复。这将允许重复使用现有架构。

【讨论】:

  • 我认为他的 Create Table 语句不是问题 - 在 5.1 版上对我来说效果很好 - 但旧版本可能存在差异。我认为问题是试图在单个 TADOQuery 组件中执行多个语句
  • @Jason:如果是这种情况,快速更改 TADOCommand 组件可能会解决它,因为我已经使用 SQL Server 在那里执行了多个语句。正如我所说,我无法测试任何一种方式,因为我目前没有安装 MySQL。 MySQL 3.x 的文档似乎表明语法错误,但我没有看 5.1,因为海报在连接字符串中说 3.51(5.1 文档不相关)。 :-) 使用 TSQL,您必须省略 GO(它仅由 SSMS 使用),但海报的语法适用于数据类型更正。
  • 很有可能。 FWIW,我将 TAdoCommand.CommandText 设置为初始 SQL(减去创建数据库行)并调用 Execute 给出了 OP 收到的确切错误。从 TAdoCommand.CommandText 中删除 use fakeschema 行工作正常,所以我仍然倾向于在单个 TAdoQuery 中使用多个语句:)。
  • @Jason:然后,您应该编写一个示例(带代码)并发布答案。 :-)
  • 我知道我创建表的方式有点傻,因为用户可以选择完全删除所有以前的数据。对于具有基本知识的用户来说,安装 MySQL 并创建模式也不是很容易,以便我的程序可以创建表。但是,我已经将表和模式的名称硬编码到我的代码中的查询中,因此我必须在 MySQL 中使用完全相同的表名。为了将来参考,有什么好的方法可以让用户在我的应用程序中创建表名和数据库名,然后创建所述表并在查询中使用它们?
【解决方案3】:

如果您收到类似的 MySQL 错误消息

SQL 语法错误near '(quoted)'

您总是需要查看引用部分之前的代码。

在这种特殊情况下CREATE SCHEMA IF NOT EXISTS fakeschema;

documentation也很清楚这一点

从 MySQL 5.0.2 开始,CREATE SCHEMA 是 CREATE DATABASE 的同义词。

所以你不能使用这个同义词,因为你的 MySQL 服务器(低于 5.0.2 的版本)或者在这种情况下 OD​​BC 驱动程序不知道这个。

这应该消除当前错误消息

CREATE DATABASE IF NOT EXISTS fakeschema;   
USE fakeschema;  
CREATE TABLE table1(
  IDtable1 int(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,  
  Line1    varchar(45),  
  Line2    varchar(45)
);  

【讨论】:

  • 即使您删除了 create database 语句,问题仍然存在,因为 OP 试图在单个 TAdoQuery 中执行这三个语句 - 这是我的理解。当然 CREATE SCHEMA 语句不能像你现在指出的那样使用,但我相信他仍然会遇到同样的问题(我在 Delphi 7 和 MySQL 5.1 上这样做)
【解决方案4】:

不涉及 cmd.exe 的解决方案(基于@Jason 的)是使用 mysql source 命令:

cmd := '-u USER_NAME -pUSER_PASSWORD DB_NAME -e "source createFakeSchema.sql"';
ShellExecute(handle, 'open', 'mysql.exe', Pchar(cmd), 'PATH_TO_MYSQL', SW_SHOW);

【讨论】:

    【解决方案5】:

    我努力寻找如何创建数据库。我正在使用“Zeos”:

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ShellAPI, ZAbstractConnection, ZConnection, DB,
      ZAbstractRODataset, ZAbstractDataset, ZDataset;
    
    type
      TForm1 = class(TForm)
        btn1: TButton;
        ZConnection1: TZConnection;
        ZQuery: TZQuery;
        btn2: TButton;
        procedure btn1Click(Sender: TObject);
        procedure btn2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.btn1Click(Sender: TObject);
    begin
      ZConnection1.Protocol := 'mysql-5';
      ZConnection1.Database := '';
      ZConnection1.User := 'root';
      ZConnection1.Password := 'root';
      ZConnection1.Connect;
    end;
    
    procedure TForm1.btn2Click(Sender: TObject);
    var
      vSQL : string;
    begin
      ZQuery.Close;
      ZQuery.SQL.Clear;
      vSQL := 'CREATE DATABASE IF NOT EXISTS `test`';
      ZQuery.SQL.Add(vSQL);
      ZQuery.ExecSQL;
    end;
    
    end.
    

    我希望我可以帮助任何人;

    最好的问候

    【讨论】:

      猜你喜欢
      • 2018-12-28
      • 2010-11-03
      • 2010-11-04
      • 1970-01-01
      • 1970-01-01
      • 2013-02-21
      • 2010-12-30
      • 1970-01-01
      • 2016-09-09
      相关资源
      最近更新 更多