capture values from a simple select query TADOQuery Delphi - mysql

I am having issues returning the value gotten from a simple SELECT query using TADOQuery
here is my code below:
dbWizconQuery.SQL.Clear;
dbWizconQuery.SQL.Add('SELECT * FROM test');
tb_wizconValues.Items.Add('' + dbWizconQuery.SQL.GetText);
dbWizconQuery.ExecSQL;
processed := IntToStr(dbWizconQuery.FieldByName ('input' ).Value);
tb_wizconValues.Items.Add('' + processed);
I get the first print out in my textbox ok, with the SQL String
but then i dont get the value coming out.
Can you see why this might be?
Processed is a String and input is an INT(5) which comes out AsString
Kind Regards,
Jordan

in delphi ExecSQL is used when you want to do an
UPDATE,INSERT,DELETE
when you want to do a select call open or just set the query to
active := true;
you can get multiple results back by using this code:
dbWizconQuery.SQL.Clear;
dbWizconQuery.SQL.Text := 'SELECT * FROM test';
dbWizconQuery.Open; // or dbWizconQuery.Active := True;
while not dbWizconQuery.eof do
begin
ShowMessage(dbWizconQuery.FieldByName('FieldName').AsString); // this shows the fields value
dbWizconQuery.Next; //use this line or you will get an infinite loop
end;
dbWizconQuery.Close; //closes the dataset
for executing statements like UPDATE,INSERT,DELETE use it like this:
dbWizconQuery.SQL.Text := 'DELETE FROM test WHERE ID = 1';
dbWizconQuery.ExecSQL;

ExecSQL is used for statements that don't return a rowset, such as INSERT, DELETE and UPDATE. For a SELECT, you need to use Open instead:
dbWizconQuery.SQL.Clear;
dbWizconQuery.SQL.Add('SELECT * FROM test');
tb_wizconValues.Items.Add('' + dbWizconQuery.SQL.GetText);
dbWizconQuery.Open;
processed := IntToStr(dbWizconQuery.FieldByName ('input' ).Value);
tb_wizconValues.Items.Add('' + processed);
For more info, see the documentation for TDataSet

Related

Duplicate problem in MySQL with autoincrement id

I have an issue with my database.
Table structure is:
Table name: sales
sale_id (autoincrement)
date (datetime)
total (decimal)
etc.
I have 2 computers, one is "the server" and the other is "the client", when I Insert in "sales" sometimes the database saves more than 1 record, it's an issue kind of random because one day could be normal just save 1 record as is but other day could save 2 or more duplicates.
My code is:
qry1.SQL.Text := 'SELECT * FROM sales '
+ 'WHERE sale_id = 1';
qry1.Open;
qry1.Insert;
qry1.FieldByName('date').AsDateTime := Date;
qry1.FieldByName('total').AsFloat := total;
qry1.Post;
saleId := qry1.FieldByName('sale_id').AsInteger;
qry1.Close;
// Code to save sale details using saleId.
I'm using Delphi 10.3 + ZeosLib 7.2.6-stable + MySQL 8.0
I opened the ports in the server so I have a direct connection to MySQL, I don't know what could be happening
Hope you can help me
Update----
Thanks for your kind answers,
#nbk Yes, I did it already.
#A Lombardo I used "where" to get just 1 record and then I use the query to insert the new one similar to use TTable but instead of load the hole table I just get one record and I can insert (qry.Insert),
#TheSatinKnight not only I get two records, sometimes I get 3 or more, but makes sense probably the keayboard is not working well and could send "enter" key more than once.
#fpiette, I will do ti right now.
I will keep you posted.
There are better ways to accomplish an insert than to open a TZTable and inserting on that open table.
As another approach, drop 2 TZQuery (NOT TZTable) on your form (which I'll assume is TForm1 - change as appropriate).
Assuming the name is ZQuery1 and ZQuery2.
Set its connection property the same as your TZTable, so it uses the same connector.
Set ZQuery1.SQL property to 'Insert into sales (date, total) values (:pdate, :ptotal)' //(w/o quotes)
Set ZQuery2.SQL property to 'select last_insert_id() as iddb'
now add the Function below to your form's Private delcaration
TForm1 = class(TForm)
ZQuery1: TZQuery; //added when dropped on form
ZQuery2: TZQuery;
private
{ Private declarations }
function AddNewSale(SaleDate: TDateTime; Total: Double): Integer; //add this line
public
{ Public declarations }
end;
and then add the following code to your form's methods
var
Form1: TForm1;
implementation
{$R *.dfm}
function TForm1.AddNewSale(SaleDate: TDateTime; Total: Double): Integer;
begin
ZQuery1.ParamByName('pdate').AsDateTime := SaleDate;
ZQuery1.ParamByName('ptotal').AsFloat := Total;
ZQuery1.ExecSQL; //*Execute* the Insert - Only "open" SQL that returns a result set
//now the record has been added to your DB
if ZQuery1.RowsAffected = 1 then //check to ensure it was inserted
begin
ZQuery2.Open;
try
Result := ZQuery2.FieldByName('iddb').AsInteger;
finally
ZQuery2.Close;
end;
end
else
result := -1;//indicate error by returning negative value
end;
now in the place you want to insert the record, simply call this function:
var
ReturnValue: Integer;
begin
ReturnValue := AddNewSale(Date, total);
if ReturnValue < 0 then
//error happened
else
begin
//Everything worked
end;
end;
Thanks again for all your kind answers.
At the end the problem was keyboard, It had a problem with "Enter" key, so when you pressed it, it send more than one pulsation so #TheSatinKnigh your approach was correct
#fpiette I created the log file and I figured out as you said the request had been executed twice or more.
I know maybe it is a silly thing for a programmer because I was disabling the button to late, sorry for that
#A Lombardo thanks for you code I like it better than mine I will use it

Delphi - DataSet creating too many connections in MySQL

I am having a problem using the TFDDataSet component in my application.
I have a function that fetch many times if a customer has new orders. If it returns empty the function ends.
...
fdm_XMLREsumo.Close;
fdm_XMLREsumo.Active := false;
_DataSetJSON := SM.GetXMLResumoChave( pEnt_ID, pChave); //See Edit 1
_DataSet.Close;
_DataSet := TFDJSONDataSetsReader.GetListValueByName( _DataSetJSON, sXMLResumo );
_DataSet.Open; <-- here's the problem
if not _DataSet.IsEmpty then begin
exit;
end;
fdm_XMLREsumo.AppendData( _DataSet );
...
The problem is every time it executes _DataSet.Open; it creates a new connection in my DB.Because of that I'm having a too many connections exception.I've checked in my Server Properties and it is like this:
I have tried Connection.Close,_DataSet.Close, _DataSet.Free and _DataSet.Destroy but nothing worked.I read this, and it explains that even if you do _DataSet.Close the connection still exists, because DataSets work in memory.There is also this guy having a similar issue, but using Query. Does anyone know how can I manage to solve this?I am using MySQL
EDIT 1
As #CraigYoung helped me saying my example needs MCVE
SM.GetXMLResumoChave method:
Here it uses a connection to the database that is closed at the end of the function. Already debugged, and here it does not leave an open connection in MySQL Proccess List
function TDAOXMLResumo.GetXMLResumoChave(xEnt_id: Integer; xChave: String): TFDJSONDataSets;
begin
if not oSM.FDConn.Connected then
oSM.FDConn.Connected := true;
QueryPesquisa.SQL.Clear;
QueryPesquisa.SQL.Text :=
' select * from table' +
' where ent_id = :ent_id ' +
' and xre_chNFe = :xre_chNFe ';
QueryPesquisa.ParamByName('ent_id').Asinteger := xEnt_id;
QueryPesquisa.ParamByName('xre_chNFe').Asstring := xChave;
Result := TFDJSONDataSets.Create;
//TFDJSONDataSetsWriter.ListAdd Opens the Query that is passed as parameter and store the data as JSON in the TFDJSONDataSets (Result) object
TFDJSONDataSetsWriter.ListAdd(Result, sXMLResumo, QueryPesquisa);
//Closing the Query
QueryPesquisa.Close;
//Closing the Connection
oSM.FDConn.Close;
end;`
Basically, the _DataSet is only receiving a JSON List here: _DataSet := TFDJSONDataSetsReader.GetListValueByName( _DataSetJSON, sXMLResumo );, and then open it to access the data in it.

dbExpress how to show result from query?

var
Connection: TSQLConnection;
SqlSet:TSQLDataSet;
begin
Connection := TSQLConnection.Create(nil);
SqlSet := TSQLDataSet.Create(nil);
SqlSet.SQLConnection:=Connection;
Connection.DriverName := 'MySQL';
Connection.GetDriverFunc := 'getSQLDriverMYSQL';
Connection.LibraryName := 'dbxmys.dll';
Connection.VendorLib := 'libmysql.dll';
Connection.LoginPrompt:=False;
Connection.Params.Values['Database']:=('shadowxx1');
Connection.Params.Values['User_Name']:=('shadowxx1');
Connection.Params.Values['Password']:=('shadowxx1');
Connection.Params.Values['HostName']:=('shadowxx1');
Connection.Open;
Connection.Connected:=True;
SqlSet.CommandType:=ctQuery;
SqlSet.CommandText:= 'SELECT VERSION()';
SqlSet.ExecSQL;
Connection.Close;
Connection.Free;
SqlSet.Free;
end;
Code working , but , how to show result of query or extract it to the grid???
I simply dont find this information, in ADO it was smth like this
DataSrc := TDataSource.Create(Self);
DataSrc.DataSet := ADOQuery;
DataSrc.Enabled := true;
DBGrid1.DataSource := DataSrc;
If someone can - give some examples
And like this dont work
You're using the wrong method. In any of the TDataSet descendants that have it, ExecSQL is for executing queries that return no result set, such as INSERT, UPDATE, DELETE, or CREATE TABLE. See, for instance, TSQLQuery.ExecSQL (emphasis mine)
Executes a query that does not return a set of records.
Call ExecSQL to execute an SQL command that does not return a set of records. This command is a query other than a SELECT query, such as an INSERT, UPDATE, DELETE, or CREATE TABLE query.
Use TSQLQuery.Open to return rows from a SELECT. Something like this should work (untested - I don't use MySQL or DBExpress):
var
Qry: TSQLQuery;
VersionString: String;
// Set up your connection as above, and open it
Qry := TSQLQuery.Create(nil);
Qry.SQLConnection := Connection;
Qry.SQL.Text := 'SELECT VERSION() as DBVersion';
Qry.Open;
if not Qry.IsEmpty then
VersionString := Qry.FieldByName('DBVersion').AsString
else
VersionString := 'No results found';
Qry.Close;
For more information (including step-by-step tutorials), see Using DBExpress Components at the Delphi docwiki. (The one I've linked is for the current Delphi version, but the basic steps for DBExpress are the same since it was introduced.)
If you want a basic video tutorial for using DBExpress in Delphi, you can try DBExpress Data Access Components in Delphi - Delphi 101. I haven't watched it, but it was posted by Embarcadero, the makers of Delphi.

Delphi, ADO, MySQL: checking whether an empty set was returned

The version of Delphi is 7.
I'm sending a query to a MySQL database. What can be returned is either a set of data rows or simply an empty set. Nothing unusual. But I have no idea how to make a checking mechanism that will check whether it is a set of data or an empty set.
Here's some code:
var
Q: TADOQuery;
begin
Q := TADOQuery.Create(self);
Q.Connection := ADOConnection;
Q.SQL.Add('CALL get_shopping_cart_list()'); // Call stored procedure
Q.Open; // Send query and get some
// results back
// PSEUDOCODE
// IF get_shopping_cart_list() RETURNS A NON-EMPY SET THEN
// SHOW WHAT WE HAVE
// ELSE
// SHOW A MESSAGE THAT SAYS 'EMPTY SET'
Q.Free;
end;
Depending on Delphi version it can be either
if Q.IsEmpty then ...
or
if Q.BOF and Q.EOF then ...
You can also dive into Microsoft ADO. As long as there are no multiple statements in your query, Q.RecordSet.EOF and Q.RecordSet.BOF should do.
http://msdn.microsoft.com/library/windows/desktop/ms675787.aspx
http://www.w3schools.com/ado/ado_ref_recordset.asp
http://msdn.microsoft.com/library/windows/desktop/ms677539.aspx
Also please do not forget to guard memory management of errors.
Q := TADOQuery.Create;
try
.... do this or that ....
.... do this or that ....
.... do this or that ....
finally
Q.free;
end;

Inserting a JSON Object into a database

I am building a DataSnap server in Delphi XE2, and I'm having trouble figuring out the best way to insert the JSON Object that the client sends me into a Database.
Here's the format of the object I'm receiving:
{"PK":0,"FIELD1":"EXAMPLE","FIELD2":5, "DATE":""}
The solution I found was the following code
with qryDBMethods do
begin
SQL.Text := 'SELECT * FROM Table';
Open;
Append;
FieldByName('PK') .AsInteger := StrToInt(newId.ToString)
FieldByName('FIELD1').AsString := Object.Get('FIELD1').JsonValue.Value;
FieldByName('FIELD2').AsInteger := StrToInt(Object.Get('FIELD2').JsonValue.Value);
FieldByName('DATE') .AsDateTime:= Now;
Post;
After that, I would have my query component made into a JSON Object and returned to my client, but problem is, this is going to be a big application with dense tables and so doing a "SELECT * " every time I want to insert something isn't ideal. What is the best way to do this?
Try using a INSERT sentence instead.
with qryDBMethods do
begin
SQL.Text := 'INSERT INTO Table (PK, FIELD1, FIELD2) VALUES (:PK, :FIELD1, :FIELD2)';
ParamByName('PK') .Value:= StrToInt(newId.ToString)
ParamByName('FIELD1').Value := Object.Get('FIELD1').JsonValue.Value;
ParamByName('FIELD2').Value:= StrToInt(Object.Get('FIELD2').JsonValue.Value);
ExecSQL();
If what the problem is the amount of data when you open a Select * From Table, why not do something like Select * From Table Where 1 <> 1?
This way you would be able to insert while not loading any result.
Other option would to make an Insert script instead.