我目前正在编写一个使用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;
答案 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查询)并将其从用户界面相关表单中删除,无论如何,