Receiving data from an SQL table in Delphi - mysql

I have a form which needs to fetch and display data from a MYSQL database.
The SQL code which I have written works fine, as I have tried to execute it within MYSQL.
I have also used a similar format of code to the one in my form, within another form, to fetch and display SQL data. The code works perfectly in the other form.
However, my code for this form does not seem to be receiving/displaying the data from the SQL table.
Here's a snippet of the code written for the OnShow event of the form.
procedure TfrmEditBooking.FormShow(Sender: TObject);
var
CustName: string;
begin
if SelectedID > 0 then
begin
with frmBookingData.ADOQuery1 do
begin
Open;
SQL.Clear;
SQL.Add('SELECT Name, Surname ' +
'FROM customers_main ' +
'WHERE customers_main.idcustomers_main ' +
'IN ' +
'(SELECT bookings_main.customers_main_idcustomers_main ' +
'FROM bookings_main ' +
'WHERE bookings_main.idbookings_main = ' + IntToStr(SelectedID) + ')');
ExecSQL;
CustName := FieldByName('Surname').AsString + ' ' + FieldByName('Name').AsString;
Label1.Caption := CustName;
Close;
end;
end;
end;

One uses 'execsql' when one is not expecting to receive a cursor into a dataset (in other words, use 'execsql' with 'update', 'insert' and 'delete' statements but not with 'select').
You should replace the 'execsql' command with 'open' ... and remove the 'open' before 'sql.clear'.
Don't use a subquery when you should be using a join.
I think that your code ought to look like this
procedure TfrmEditBooking.FormShow(Sender: TObject);
begin
if SelectedID > 0 then
with frmBookingData.ADOQuery1 do
begin
SQL.Clear;
SQL.Add ('SELECT Name, Surname ');
sql.add ('FROM customers_main inner join bookings_main');
sql.add ('on customers_main.idcustomers_main = ');
sql.add ('bookings_main.customers_main_idcustomers_main');
sql.add ('where bookings_main.idbookings_main = :p1');
sql.params[0].asinteger:= SelectedID;
open;
Label1.Caption := fieldbyname ('name').asstring + ' ' +
fieldbyname ('surname').asstring;
Close;
end;
end;

To get this running you should change it to
procedure TfrmEditBooking.FormShow(Sender: TObject);
var
CustName: string;
begin
if SelectedID > 0 then
begin
with frmBookingData.ADOQuery1 do
begin
Close; // close first
SQL.Clear;
SQL.Add(
'SELECT Name, Surname '+
'FROM customers_main '+
'WHERE customers_main.idcustomers_main '+
'IN '+
'(SELECT bookings_main.customers_main_idcustomers_main '+
'FROM bookings_main '+
'WHERE bookings_main.idbookings_main = '+IntToStr(SelectedID)+')');
Open; // open the query
if not Eof then
CustName := FieldByName('Surname').AsString+' '+FieldByName('Name').AsString
else
CustName := 'not found';
Close; // close when finished
end;
Label1.Caption := CustName;
end;
end;
But you should get some (negative) side effects, if frmBookingData.ADOQuery1 is already in use for something different

Related

Showing first and last name in statusbar

I am a beginner in Delphi, and I would like to show first and last name in the StatusBar instead of the username.
Here is my code:
procedure TForm1.Button1Click(Sender: TObject);
begin
with Login do
begin
active := false;
sql.Clear;
sql.Text := 'SELECT korisnicko, lozinka from operateri where korisnicko = ' + quotedstr(edtkorisnicko.Text) + ' and lozinka = ' + quotedstr(edtlozinka.Text);
active := true;
if Login.RecordCount <> 0 then
begin
form1.Hide();
form2.statusbar1.panels[0].text:= 'Korisnik: ' + edtKorisnicko.Text;
form2.showmodal();
end
else
begin
ShowMessage('Korisničko ime ili lozinka nisu validni!');
end;
end;
"Korisnicko or edtKorisnicko" standing for "username".
Given that your own answer shows the desired name is stored in the ime_prezime field of the database record you are searching for, you can simply retrieve that field in the very same SELECT query that is searching for the username/password, there is no need to run a 2nd query to get that field value separately, eg:
procedure TForm1.Button1Click(Sender: TObject);
begin
Login.Close;
Login.SQL.Text := 'SELECT ime_prezime from operateri where korisnicko = ' + QuotedStr(edtkorisnicko.Text) + ' and lozinka = ' + QuotedStr(edtlozinka.Text);
Login.Open;
Login.First;
if not Login.Eof then
begin
Form1.Hide();
Form2.StatusBar1.Panels[0].Text := 'Korisnik: ' + Login.FieldByName('ime_prezime').AsString;
Form2.ShowModal();
end
else
begin
ShowMessage('Korisničko ime ili lozinka nisu validni!');
end;
end;
There is answer. :)
procedure TForm1.Button1Click(Sender: TObject);
begin
with Login do
begin
active := false;
sql.Clear;
sql.Text := 'SELECT korisnicko, lozinka from operateri where korisnicko = ' + quotedstr(edtkorisnicko.Text) + ' and lozinka = ' + quotedstr(edtlozinka.Text);
active := true;
if Login.RecordCount <> 0 then
begin
active := false;
sql.Clear;
sql.Text := 'SELECT ime_prezime FROM operateri WHERE korisnicko = ' + quotedstr(edtkorisnicko.Text);
active := true;
form1.Hide();
form2.statusbar1.panels[0].text := 'Korisnik: ' + Login.FieldByName('ime_prezime').Text;
form2.showmodal();
end
else
begin
ShowMessage('Korisničko ime ili lozinka nisu validni!');
end;
end;

Insert the records of a dbf file into a table in MS Access database using Delphi

I am trying to insert the records of a dbf file into a table in a MS Access database that I have already created.
The dbf file's name is tab1.dbf and it has three columns: cl1, cl2, cl3.
The MS Access database name is db1 and it has one table tb2 with three columns: cl1, cl2, cl3.
I have connected Delphi to the MS Access database using ADOConnection1.
To insert the dbf file's records, I have to click in a Button1 with OpenDialog1
The code I use is this :
procedure TForm1.Button1Click(Sender: TObject);
var importdir,ipo : string;
begin
if form1.OpenDialog1.Execute then
begin
importdir:= extractfiledir(form1.OpenDialog1.FileName);
ipo:= form1.OpenDialog1.FileName ;
end;
form1.Edit1.Text:= importdir;
ADOConnection1.Execute('insert into tab2 SELECT * FROM [ database = '+ipo+' ].tab1' );
end;
but when i execut the form1 i have this error message :
name of the file is incorrect
can you help me guys ?
Here after is one simple solution. It simple because it assume the Access database structure is the same as the dBASE structure. You'll get started with this example that you'll adapt to your needs.
procedure TDbfToAccessWithAdoForm.DbfToAccessButtonClick(Sender: TObject);
var
Fld : Integer;
FldValue : Variant;
InsertSQL : String;
begin
ADOConnectionAccess.Connected := TRUE;
ADOConnectionDbf.Connected := TRUE;
ADOQueryDbf.SQL.Text := 'Select * from Clients';
ADOQueryDbf.Open;
// Build the parametrized INSERT statement
InsertSQL := 'insert into Clients(';
for Fld := 0 to ADOQueryDbf.FieldCount - 1 do
InsertSQL := InsertSQL + ADOQueryDbf.Fields[Fld].FieldName + ',';
// Remove extra coma
Delete(InsertSQL, Length(InsertSQL), 1);
InsertSQL := InsertSQL + ') values (';
for Fld := 0 to ADOQueryDbf.FieldCount - 1 do
InsertSQL := InsertSQL + ':' + ADOQueryDbf.Fields[Fld].FieldName + ',';
// Remove extra coma
Delete(InsertSQL, Length(InsertSQL), 1);
InsertSQL := InsertSQL + ')';
while not ADOQueryDbf.Eof do begin
ADOQueryAccess.SQL.Text := InsertSQL;
for Fld := 0 to ADOQueryDbf.FieldCount - 1 do begin
FldValue := ADOQueryDbf.Fields[Fld].Value;
// Here you can do whatever conversion is required
if FldValue = Null then begin
if ADOQueryDbf.FieldDefList[Fld].DataType = ftDateTime then
FldValue := 0 // My Access table doesn't like empty datetime
else
FldValue := ' '; // My Access table doesn't like empty string
end;
ADOQueryAccess.Parameters.ParamByName(ADOQueryDbf.Fields[Fld].FieldName).Value := FldValue;
end;
ADOQueryAccess.ExecSQL;
ADOQueryDbf.Next;
end;
ADOQueryDbf.Close;
ADOQueryAccess.Close;
end;
You should add error checking and try/finally or try/except. I let you do it as you do usually.

Can I make a quickly SQL call in the MainThread? Delphi

I have several SQL calls in my Delphi VCL application which uses FireDac to call a MySQL Server to get some data.
However, I am doing all this calls inside the UIThread because they take only a couple of milliseconds. Like the example below:
This is my UI Form
type
TfrmCadPlacas = class(TForm)
lblNumeroDaPlaca: TLabel;
...
...
...
procedure TfrmCadPlacas.btnSalvarClick(Sender: TObject);
begin
// ------------- SQL -------------
if not EstaEditando then
begin
InserirPlaca(Placa, Marca, Modelo, Cor, IDLote, IDHistorico,
dmDados.IDUsuario, dmDados.IDLoteamento);
ShowMessage(SMsgPlacaInseridaSucesso);
end;
end;
InserirPlaca procedure
procedure InserirPlaca(Placa, Marca, Modelo, Cor:string; IDLote, IDHistorico, IDUsuario, IDLoteamento: Integer);
var
qryInserir: TFDQuery;
begin
qryInserir := TFDQuery.Create(nil);
with qryInserir do
begin
Connection := dmDados.FDConnection;
Active := False;
SQL.Clear;
SQL.Add('INSERT INTO ' + T_PLACAS);
SQL.Add('(' + C_PLACA + ', ');
SQL.Add(C_MARCA + ', ');
SQL.Add(C_MODELO + ', ');
SQL.Add(C_COR + ', ');
SQL.Add(C_ID_LOTE + ', ');
SQL.Add(C_ID_HISTORICO + ') ');
SQL.Add('VALUES (:' + C_PLACA + ', ');
SQL.Add(':' + C_MARCA + ', ');
SQL.Add(':' + C_MODELO + ', ');
SQL.Add(':' + C_COR + ', ');
SQL.Add(':' + C_ID_LOTE + ', ');
SQL.Add(':' + C_ID_HISTORICO + ') ');
Params[0].AsString := Placa;
Params[1].AsString := Marca;
Params[2].AsString := Modelo;
Params[3].AsString := Cor;
Params[4].AsInteger := IDLote;
Params[5].AsInteger := PesquisarHistorico(IDLote);
ExecSQL;
end;
end;
As you can see, I am performing a MySQL Server request in the MainThread.
After watching some classes I noticed it is wrong to perform heavy operation in the UIThread as it should be only for GUI. In my case, the operation is pretty fast so it doesn't disturb the UI, if the internet connection is good.
Should I put this MySQL Server request in a background Thread?

Syntax error in SQL SELECT INTO FROM from Delphi

I am trying to insert a new record into my database using SQL, but it keeps telling me that I have a syntax error in the from clause.
I don't see the error.
Here is the code:
procedure TForm1.BitBtn7Click(Sender: TObject);
var
sCategoryName :string;
begin
sCategoryName := InputBox('Category Name', 'Please enter your category name that you would like to add','');
with dmRecords do
begin
qryRecords.Active := False;
qryRecords.SQL.Add('INSERT INTO [Category of Income]([Category Name])');
qryRecords.SQL.Add('VALUES ' + '(' + QuotedStr(sCategoryName) + ')');
qryRecords.ExecSQL;
qryRecords.SQL.Add('SELECT * FROM [Category of Income] ORDER BY [Category ID]');
qryRecords.Active := True;
end;
end;
You haven't cleared the SQL from the previous statement. When you open the query, SQL has three lines of text.
Add qryRecords.SQL.Clear before adding the SELECT statement.

How can I avoid storing duplicates in the database in this code?

I have a user registration process which stores user info to my database using MYDAC components. Currently it allow duplicate users, which is not my intention. My code is below, but I don't know where the problem is.
procedure TForm1.Button1Click(Sender: TObject);
begin
if (edit1.Text <> '') and (edit2.Text <> '') and (edit3.Text <> '') and
(edit4.Text <> '') then
begin
MyQuery1.Close;
MyQuery1.SQL.Text := 'select * from uyeler '+
'where nick=:0 and mail=:0 and site=:0';
MyQuery1.Params[0].AsString:=edit1.text;
MyQuery1.Params[0].AsString:=edit2.text;
MyQuery1.Params[0].AsString:=edit3.text;
MyQuery1.open;
if MyQuery1.RecordCount = 0 then
MessageDlg('The same information! Try again.', mtError, [mbOK], 0)
else
MyQuery1.Close;
MyQuery1.SQL.Text := 'INSERT INTO uyeler (nick, mail, site, sifre) VALUES '+
'(:nick, :mail, :site, :sifre)';
MyQuery1.ParamByName('nick').AsString := Edit1.text;
MyQuery1.ParamByName('mail').AsString := Edit2.text;
MyQuery1.ParamByName('site').AsString := Edit3.text;
MyQuery1.ParamByName('sifre').AsString := Edit4.text;
MyQuery1.Execute;
Button1.Enabled := False;
MessageDlg('Mission complate!', mtInformation, [mbOK], 0);
Edit1.Clear;
Edit2.Clear;
Edit3.clear;
Edit4.Clear;
PageControl2.Visible := False;
PageControl1.Visible := True;
end
else
begin
MessageDlg('Information is missing! Try again.', mtWarning,[mbOK],0);
end;
end;
How can I prevent signing up with the same? What should I do in this case?
I would typically use unique indexes on the underlying MySQL table to enforce this.
You're checking the wrong result. You need to change your test to
if MyQuery1.RecordCount > 0 then // At least one match found already
Better yet, if MyDac supports it, is to use
if not MyQuery1.IsEmpty then // row already exists.
Actually, you have more issues than that, though. You have a mismatched begin and end block, because right now you're always running the insert part of the method. As #TLama says, you're also using the same pameter multiple times, assigning nick, mail, and site the all the same value. Use named parameters instead (shown below in both the SQL and the parameter assignments).
procedure TForm1.Button1Click(Sender: TObject);
var
UserExists: Boolean;
begin
Button1.Enabled:=false;
if (edit1.Text <> '') and (edit2.Text <> '') and
(edit3.Text <> '') and (edit4.Text <> '') then
begin
MyQuery1.Close;
MyQuery1.SQL.Text :=' select* from uyeler '+
'where nick=:nick and mail=:mail and site=:site';
MyQuery1.ParamByName('nick').AsString:=edit1.text;
MyQuery1.ParamByName('mail').AsString:=edit2.text;
MyQuery1.ParamByName('site').AsString:=edit3.text;
MyQuery1.open;
try
UserExists := not MyQuery1.IsEmpty;
finally
MyQuery1.Close;
end;
if UserExists then
MessageDlg('The same information! Try again.', mtError,[mbOK],0)
else
begin // <<--- Added begin
MyQuery1.SQL.Text :=' INSERT INTO uyeler (nick, mail, site, sifre) VALUES '+
'(:nick, :mail, :site, :sifre)';
MyQuery1.ParamByName('nick').AsString := Edit1.text;
MyQuery1.ParamByName('mail').AsString := Edit2.text;
MyQuery1.ParamByName('site').AsString := Edit3.text;
MyQuery1.ParamByName('sifre').AsString := Edit4.text;
try
MyQuery1.Execute;
finally
MyQuery1.Close;
end;
end; // <------------ Moved end from below where marked
MessageDlg('Mission complate!', mtInformation,[mbOK],0);
Edit1.Clear;
Edit2.Clear;
Edit3.clear;
Edit4.Clear;
PageControl2.Visible:=false;
PageControl1.Visible:=true;
end // <------------- removed extra end caused by addition above
else
MessageDlg('Information is missing! Try again.', mtWarning,[mbOK],0);
end;
IMO the answer posted by #Ken White should work fine, but since you are finding troubles. I suggest you to try with this code. Its just the difference in the executing the queries.
I am considering the field datatypes to be Char or VarChar, hence " " while entering the data values
procedure TForm1.Button1Click(Sender: TObject);
begin
Button1.Enabled:=false;
if (edit1.Text <> '') and (edit2.Text <> '') and
(edit3.Text <> '') and (edit4.Text <> '') then
begin
MyQuery1.SQL.Clear;
MyQuery1.SQL.Add(' select* from uyeler where nick="'+edit1.text+'"' +
'and mail="'+edit2.text+'" and site="'+edit3.text+'"');
MyQuery1.Execute;
if not MyQuery1.IsEmpty then //--- can also use MyQuery1.RecordCount >0
MessageDlg('The same information! Try again.', mtError,[mbOK],0)
else
begin //--- no duplicates present
MyQuery1.SQL.Clear;
MyQuery1.SQL.Add(' INSERT INTO uyeler (nick, mail, site, sifre) VALUES '+
'("'+edit1.text+'", "'+edit2.text+'","'+edit3.text+'", "'+edit4.text+'")');
try
MyQuery1.Execute;
finally
MyQuery1.SQL.Clear;
end;
MessageDlg('Mission complate!', mtInformation,[mbOK],0);
Edit1.Clear;
Edit2.Clear;
Edit3.clear;
Edit4.Clear;
PageControl2.Visible:=false;
PageControl1.Visible:=true;
end;
end;
else
MessageDlg('Information is missing! Try again.', mtWarning,[mbOK],0);
end;