Delphi 7 SQL参数在Select Statement中找到,但不是Insert Statement

时间:2015-08-26 17:27:31

标签: sql delphi

我目前正在编写一个使用SQL和Access 2003数据库的Delphi 7程序。

该单元通过公共变量(这是frmLogin.sCode)从前一个单元接收一个5位数的代码。在表单激活时,程序将执行SQL查询以显示来自与sCode匹配的tblStudents的记录。该语句使用ParamByName行并且工作正常。

如果未找到匹配项,则会显示一条消息,但该用户没有选项,只需单击添加用户按钮即可。然后提示用户将所有细节输入到程序中,然后将其传递给设置SQL插入语句的类。但是,现在出现问题,因为显示一条消息,指出未找到参数用户名。我无法理解为什么会在运行Select语句时找到它。请有人帮忙吗?

procedure TfrmProfilePage.FormActivate(Sender: TObject);
begin
  //Instantiates the object.
  objProfilePage := TProfilePage.Create;
  sSQL := objProfilePage.SelectSQL;
  ExecuteSQL(sSQl);
end;

procedure TfrmProfilePage.ExecuteSQL(sSQL : String);
begin
  With dmTextbookSales do
    Begin
      dbgrdDisplay.DataSource := dsProfilePage;
      qryProfilePage.SQL.Clear;
      qryProfilePage.SQL.Add(sSQL);
      qryProfilePage.Parameters.ParamByName('Username').Value := frmLogin.sCode;
      qryProfilePage.Open;
      If qryProfilePage.RecordCount = 0
        Then
          Begin
            ShowMessage('Please click on the "Add Details" button to get started.');
            btnChange.Enabled := False;
            btnSelling.Enabled := False;
            btnBuying.Enabled := False;
          End;
    End;
end;

procedure TfrmProfilePage.GetValues(VAR sStudentName, sStudentSurname, sCellNumber, sEmailAddress : String; VAR iCurrentGrade : Integer);
begin
  ShowMessage('Fields may be left blank, but users wishing to sell textbooks should enter at least one contact field.');
  sStudentName := InputBox('Name','Please enter your first name:','');
  sStudentSurname := InputBox('Surame','Please enter your surname:','');
  iCurrentGrade := StrToInt(InputBox('Current Grade','Please enter your current grade:',''));
  sCellNumber := InputBox('Cellphone Number','Please enter your cellphone number:','');
  sEmailAddress := InputBox('Email Address','Please enter your email address:','@dainferncollege.co.za');
end;

procedure TfrmProfilePage.btnAddClick(Sender: TObject);
begin
  GetValues(sStudentName, sStudentSurname, sCellNumber, sEmailAddress, iCurrentGrade);
  sSQL := objProfilePage.InsertSQL;
  ExecuteSQL(sSQL);
  btnChange.Enabled := True;
  btnSelling.Enabled := True;
  btnBuying.Enabled := True;
end;

以下代码是从链接类clsProfilePage:

获得的
function TProfilePage.InsertSQL: String;
begin
  Result := 'INSERT INTO tblStudents (' + '[StudentID]' + ',' + '[StudentName]' + ',' + '[StudentSurname]' + ',' + '[CurrentGrade]' + ',' + '[CellNumber]' + ',' + '[EmailAddress]' + ') VALUES (' + 'Username' + ',' + QuotedStr(fStudentName) + ',' + QuotedStr(fStudentSurname) + ',' + IntToStr(fCurrentGrade) + ',' + QuotedStr(fCellNumber) + ',' + QuotedStr(fEmailAddress) + ')';
end;

function TProfilePage.SelectSQL: String;
begin
  Result := 'SELECT * FROM tblStudents Where StudentID = Username';
end;

1 个答案:

答案 0 :(得分:1)

您的INSERT声明错误。您需要先添加参数,然后才能设置参数值。在Delphi中,您可以在SQL语句中的参数名称之前使用:执行此操作。

此外,Open仅在执行 SELECT 时使用。 INSERT UPDATE DELETE 不返回行集,因此您必须使用ExecSQL(数据集方法,而不是改为使用冲突名称的函数。

(虽然我们正在使用它,但从不在SQL数据集上使用RecordCount - 它需要检索所有行以获取计数,并且在执行除之外的任何操作时都不相关无论如何选择ExecSQL执行的操作应使用RowsAffected代替,它会告诉您操作影响的行数。

(如果您需要计算行数,请执行SELECT COUNT(*) AS NumRecs FROM YourTable WHERE <some condition>,然后使用NumRecs访问FieldByName字段。)

将返回INSERT语句的函数更改为类似的函数(#13中的Result是回车符,这可以防止必须在每行的末尾手动插入空格分开SQL单词):

function TProfilePage.InsertSQL: String;
begin
  Result := 'INSERT INTO tblStudents ([StudentID],'#13 +
            '[StudentName], [StudentSurname],'#13 +
            '[CurrentGrade], [CellNumber], [EmailAddress])'#13 +
            'VALUES (:Username, :StudentName,'#13 +
            ':StudentSurname, :CurrentGrade,'#13 +
            ':CellNumber, :EMailAddress)';
end;

然后,您可以将其与ParamByName一起使用,而无需通过QuotedStr和连接跳过所有环节:

procedure TfrmProfilePage.AddUser;
begin
  with dmTextbookSales do
  begin
    qryProfilePage.SQL.Text := InsertSQL;
    qryProfilePage.Parameters.ParamByName('Username').Value := frmLogin.sCode;
    qryProfilePage.Parameters.ParamByName('StudentName').Value := frmLogin.sUserName;
    // Repeat for other parameters and values - you have to set every
    // single parameter. To skip, set them to a null variant.

    // Execute the INSERT statement          
    qryProfilePage.ExecSQL;    

    // See if row was inserted, and do whatever.
    If qryProfilePage.RowsAffected > 0 then
      ShowMessage('User added successfully');
   // Perform a SELECT to populate the grid contents with the new
   // rows after the update
  end;
end;

我强烈建议您重新考虑此代码。这是非常复杂的,它需要太多来完成一个简单的任务(添加一个新用户)。

如果是我,我将使用专门用于执行INSERT操作的单独查询,您可以在设计时设置SQL,并为参数设置正确的类型。对象检查器。然后在运行时,只需设置参数值并在该插入查询上调用ExecSQL,并刷新SELECT查询以反映新行。它避免了所有的噪音和混乱(以及一些不必要的函数调用和错综复杂的SQL构建,打开和关闭SELECT查询等。)

(它还允许您删除那个可怕的with语句,这会导致难以发现的错误和难以维护的代码。)

您在表单之间也存在一些不良链接,您可以从第二种表单引用frmLogin(特定表单实例)。这意味着您不能同时使用任何一个表单的多个实例,因为您已在该引用中进行了硬编码。我重新考虑使用在创建表单时传入的参数,或者在创建配置文件页面表单时使用登录表单设置的属性(或者TProfilePage是什么 - 您的帖子没有说)

最佳解决方案是将所有非UI相关代码移动到一个单独的单元(例如TDataModule,该单元旨在用于处理非可视组件,如ADO查询)并将其从用户界面相关表单中删除,无论如何,

  • 消除表单之间的耦合,允许重用代码。
  • 删除非可视数据相关组件,使表单和表单代码混乱。
  • 将业务逻辑(与用户交互无关的部分)分离到一个单独的不同位置,使其(以及使用它的代码)更易于维护。