Showing first and last name in statusbar - mysql

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;

Related

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?

Populate ComboBox with Title Case Query Result

with TdmBCElections.Create(Self) do
begin
with dmBCElections, qryParties do
begin
SQL.Clear;
if rgpParty.ItemIndex = 0 then
SQL.Text := 'SELECT StrConv(P_Surname, 3), StrConv(P_Names, 3) ' +
'FROM Parties WHERE P_Type = "HEAD"'
else
SQL.Text := 'SELECT StrConv(P_Surname, 3), StrConv(P_Names, 3) ' +
'FROM Parties WHERE P_Type = "TEACHER"';
Open;
while not Eof do
begin
cmbDetails.Items.Add(qryParties['StrConv(P_Surname, 3)'] + ', ' +
qryParties['StrConv(P_Names, 3)']);
Next;
end;
end;
end;
The code above gives me the following error message:
How do I call the table fields when StrConv is applied to them?
You can assign an alias to the fields:
with TdmBCElections.Create(Self) do
begin
with dmBCElections, qryParties do
begin
if rgpParty.ItemIndex = 0 then
SQL.Text := 'SELECT StrConv(P_Surname, 3) as ConvertedSurname, StrConv(P_Names, 3) as ConvertedNames ' +
'FROM Parties WHERE P_Type = "HEAD"'
else
SQL.Text := 'SELECT StrConv(P_Surname, 3) as ConvertedSurname, StrConv(P_Names, 3) as ConvertedNames ' +
'FROM Parties WHERE P_Type = "TEACHER"';
Open;
while not Eof do
begin
cmbDetails.Items.Add(qryParties['ConvertedSurname'] + ', ' +
qryParties['ConvertedNames']);
Next;
end;
end;
end;
Otherwise, you can use field indexes instead of names:
with TdmBCElections.Create(Self) do
begin
with dmBCElections, qryParties do
begin
if rgpParty.ItemIndex = 0 then
SQL.Text := 'SELECT StrConv(P_Surname, 3), StrConv(P_Names, 3) ' +
'FROM Parties WHERE P_Type = "HEAD"'
else
SQL.Text := 'SELECT StrConv(P_Surname, 3), StrConv(P_Names, 3) ' +
'FROM Parties WHERE P_Type = "TEACHER"';
Open;
while not Eof do
begin
cmbDetails.Items.Add(qryParties.Fields[0].AsString + ', ' + qryParties.Fields[1].AsString);
Next;
end;
end;
end;
Either way, I suggest you consider using a parameterized query instead:
SQL.Text := 'SELECT ... FROM Parties WHERE P_Type = :PType';
if rgpParty.ItemIndex = 0 then
Parameters.ParamByName('PType').Value := 'HEAD'
else
Parameters.ParamByName('PType').Value := 'TEACHER';

Writing a program to calculate Happy Numbers in Pascal. Stuck with an infinite loop

I'm writing a procedure to do the calculating. The program asks the user for any number between 1 and 9999 and then calculates whether or not that number is a happy number.
program EindEvaluatieProceduresFuncties2;
uses wincrt, math;
var lucky: boolean;
num: longint;
i, j: integer;
arr: array [1..4] of integer;
sum: integer;
procedure HappyNumber;
begin
repeat
begin
repeat
begin
i:=i+1;
//writeln('i = ',i);
arr[i]:=num mod 10;
//writeln( 'a[i] = ', arr[i] );
num:=num div 10;
//writeln ( 'n = ', num );
end;
until num=0;
//writeln('Digits are : ');
//for j:=i downto 1 do
//writeln('a[j] = ', arr[j],' ', j);
//writeln('Calculating Happy Number');
for j := i downto 1 do
sum := sum + (Sqr(arr[j]));
for j := i downto 1 do
writeln('sum = ',sum);
num := sum;
end;
until sum < 10 ;
end;
begin
lucky := false;
writeln('Please give a positive number below 10000.');
readln(num);
while ( num < 1 ) or ( num > 9999 ) do
begin
writeln('Number must be positive and less than 10000. Try again.');
readln(num);
end;
HappyNumber;
if (lucky = True) then
begin
writeln(num, ' is a happy number.');
end
else
begin
writeln(num, ' is not a happy number.');
end;
writeln('');
writeln('Press < ENTER > to end the program.');
readln;
end.
Within the procedure I have the command i := 0; as seen below:
procedure HappyNumber;
begin
repeat
begin
repeat
begin
i:=0;
i:=i+1;
This is where the problem occurs. If I do this it becomes an infinite loop, however if I place the command outside of the repeat loop then i does not reset to 0 at the beginning of every iteration of the loop, which I need it to.
I should point out that much of the code is there at the moment simply to let me see what is happening and wont be a part of the final code. Wherever I have inserted "//" are those lines.
I am aware that there is perhaps a better way I could be doing this whole program. If anyone has any suggestions for how I can make it easier, I'd also appreciate that very much.
Thank you.
Never heard of happy / unhappy numbers and found it quite interesting to solve this task :-)
There is still a lot to optimize but I think you can use it for studying.
program EindEvaluatieProceduresFuncties2;
uses SysUtils, crt ;
var input: string;
number: integer;
code: integer;
function HapyNumber(num: integer):boolean;
var
erg: integer;
digit: integer;
begin
Result := true;
erg := 0;
if num = 4 then Result := false;
if num = 4 then exit;
if num = 1 then exit;
if num = 0 then exit;
// serialize the number into digits and calculate the next number
while num > 0 do begin
digit := num mod 10;
num := num div 10;
erg := erg + digit * digit;
write(IntToStr(digit) + ' ');
end;
write(IntToStr(num) + ' ');
writeln('=' + IntToStr(erg));
Result := HapyNumber(erg);
end;
begin
repeat
writeln('Please give a positive number below 10000.' + sLineBreak + 'Number must be positive and less than 10000.' + sLineBreak + 'Type x for exit!');
readln(input);
if lowerCase(input) = 'x' then exit;
val(input, number, code);
if code <> 0 then begin
ClrScr;
writeln('Invalid number "' + input + '" !');
end
else if (number > 0) and (number <= 9999) then begin
ClrScr;
writeln('Cheking ' + IntToStr(number) + '..');
if HapyNumber(number) then writeln(number, ' is a happy number.')
else writeln(number, ' is not a happy number.');
writeln('Press enter to continue');
readln;
ClrScr;
end;
until lowerCase(input) = 'x';
end.
The important codepart is
while num > 0 do begin
digit := num mod 10;
num := num div 10;
erg := erg + digit * digit;
write(IntToStr(digit) + ' '); // just output the tmp result
end;
It serialize a number into digits (1973 will be 3 7 9 1)
I used recursion just for fun and it is not really necessary :-)

ApplyUpdates on REST with Firedac

My project uses a REST server with FireDac.
I have a generic function that makes all my Selects but when I try to ApplyUpdates if does nothings. No message, no crash, it just keeps going and the data is not reflected to the database.
My Code:
function TServerMethods.ApplyUpdates(banco, tabela : String; const DeltaList: TFDJSONDeltas; var Mensagem : String) : Boolean;
var
LApply : IFDJSONDeltasApplyUpdates;
Query : TFDQuery;
begin
mensagem := '';
result := false;
try
try
LApply := TFDJSONDeltasApplyUpdates.Create(DeltaList);
Query := CriaQuery(banco,Tabela);
Query.Open();
LApply.ApplyUpdates(banco + '.' + tabela, Query.Command);
if LApply.Errors.Count > 0 then
raise Exception.Create(LApply.Errors.Strings.ToString);
result := true;
except
on E:Exception do
begin
mensagem := 'Ocorreu um Erro na atualização: ' + #13#10 + E.Message;
end;
end;
finally
end;
end;
The GetDeltas function (the function that generates the DeltaList):
function GetDeltas(Banco, Tabela : String; MemTable : TFDMemTable) : TFDJSONDeltas;
begin
if MemTable.State in [dsInsert, dsEdit] then
MemTable.Post;
result := TFDJSONDeltas.Create;
TFDJSONDeltasWriter.ListAdd(result, MemTable);
end;
My "CriaQuery" Function:
function TServerMethods.CriaQuery(Database : String; Tabela : String = '') : TFDQuery;
var
FieldName : Boolean;
i : Integer;
begin
result := TFDQuery.Create(self);
result.Connection := Connection;
result.FetchOptions.AutoFetchAll := afAll;
result.name := 'Qry' + Database + tabela;
result.SQL.Clear;
FieldName := false;
if Trim(Tabela) <> '' then
begin
result.SQL := MontaSQL(database + '.' + tabela);
result.SQL.Add(' and 1 = 0');
result.Open();
QryCampos.First;
result.IndexFieldNames := result.Fields[1].FieldName;
for i := 0 to result.Fields.Count-1 do
begin
if (UPPERCASE(Copy(result.Fields[i].FieldName, Length(result.Fields[i].FieldName)-1,2)) = 'ID') and
(not FieldName) then
begin
result.Fields[i].ProviderFlags := [pfInUpdate, pfInWhere, pfInKey];
FieldName := true;
end
else
result.Fields[i].ProviderFlags := [pfInUpdate];
end;
result.Close;
result.SQL.Delete(result.SQL.Count-1);
end;
end;
Function that generates the bindings of the components:
procedure LinkaComponente(Campo : TField; Dono : TFmxObject; Classe : String);
var
BindSource : TBindSourceDB;
BindingList : TBindingsList;
Link : TLinkControlToField;
begin
if Dono is TForm then
begin
BindSource := TBindSourceDB.Create(Dono);
end
else
begin
BindSource := TBindSourceDB.Create(Dono.Owner);
end;
BindingList := TBindingsList.Create(BindSource.Owner);
Link := TLinkControlToField.Create(BindSource.Owner);
BindSource.DataSet := Campo.DataSet;
if Classe = 'TCheckBox' then
begin
Link.Control := Dono.FindComponent(Campo.FieldName);
Link.CustomFormat := 'ToStr(%s) <> "N"';
Link.CustomParse := 'IfThen(%s,"S","N")';
end
else if Classe = 'TFrameF2' then
begin
Link.Control := (Dono.FindComponent('Frame' + Campo.FieldName) as TFrameF2).edtFK;
end
else
Link.Control := Dono.FindComponent(Campo.FieldName);
Link.DataSource := BindSource;
Link.FieldName := Campo.FieldName;
Link.Active := true;
end;
the moment I call the applyUpdates function:
procedure TDMPadrao.DMApplyUpdates;
var
Deltas : TFDJSONDeltas;
Mensagem : String;
begin
//repetir esses comando para todas as MemTables do DM na sua ordem de dependencia
// tabelas pai antes de tabelas filhas...
try
Deltas := GetDeltas(banco, tabela, FDMemTable);
except
on E:Exception do
begin
FDMemTable.Edit;
MostraMensagemBasica('Ocorreu um Erro na atualização:' + #13#10 + E.Message);
abort;
end;
end;
if not DMClient.ServerMethodsClient.ApplyUpdates(banco, tabela, Deltas, Mensagem) then
begin
FDMemTable.Edit;
MostraMensagemBasica(Mensagem);
abort;
end;
end;
Everything works fine when I'm reading. I Only get a problem when I call the ApplyUpdates function
Thanks.
I had similar problem and I got it resolved passing the table name to Query.UpdateOptions.UpdateTableName before ApplyUpdates.
Are you doing it inside "CriaQuery"?
What is your Delphi Version?
Here is my working code, I have tested it in Delphi XE7 e XE7 Update 1:
procedure TDBDM.ApplyDeltas(const ADeltaList: TFDJSONDeltas; const TableName: string);
var
JSONDeltas: IFDJSONDeltasApplyUpdates;
Query: TFDQuery;
begin
JSONDeltas := TFDJSONDeltasApplyUpdates.Create(ADeltaList);
Query := CreateQuery(TableName);
try
Query.UpdateOptions.UpdateTableName := TableName;
JSONDeltas.ApplyUpdates(0, Query.Command);
if JSONDeltas.Errors.Count > 0 then
begin
raise Exception.Create(JSONDeltas.Errors.Strings.Text);
end;
finally
Query.Free;
end;
end;
Notes
different from your code, Query.Open is not called.
TFDMemTable.CachedUpdates must be True
Edit: Added the client side code to applyUpdates
I call this method in TFDMemTable.AfterPost event.
const
CustomerTableName = 'CUSTOMER';
procedure TCustomersDataModuleClient.ApplyUpdates;
var
Deltas: TFDJSONDeltas;
begin
Deltas := TFDJSONDeltas.Create;
TFDJSONDeltasWriter.ListAdd(Deltas, CustomerTableName, CustomersMemTable);
RestClientModule.CustomersMethodsClient.ApplyUpdates(Deltas);
CustomersMemTable.CommitUpdates;
end;

Receiving data from an SQL table in Delphi

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