I'm with a problem on Delphi, i create a simple app to test the mobile power of RadStudio, I created a simple app that put some data into some inputs and then add it to database when button is clicked. I followed this Embarcadero tutorial as starting point
The problem is that I only get one entry added, then no more entries are added or the list is not refreshed. Below some code:
Table creation:
procedure TTabbedForm.logAfterConnect(Sender: TObject);
begin
log.ExecuteDirect('CREATE TABLE IF NOT EXISTS lista (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,idCons INTEGER,nome TEXT,kms INTEGER,kmsAlarme INTEGER,quantidade INTEGER,quantidadeAlarme INTEGER,data INTEGER,dataAlarme INTEGER,alarmeMsg TEXT)');
end;
Add button code:
procedure TTabbedForm.btnGravarClick(Sender: TObject);
begin
try
SQLQueryInsert.ParamByName('idCons').AsInteger := PopupBoxTipo.ItemIndex;
SQLQueryInsert.ParamByName('nome').AsString := PopupBoxTipo.Text;
SQLQueryInsert.ParamByName('kms').AsInteger := StrToInt(kmsEdit.Text);
SQLQueryInsert.ParamByName('quantidade').AsInteger := StrToInt(qtdEdit.Text);
SQLQueryInsert.ParamByName('data').AsInteger := DateTimeToUnix(dtaEvento.Date);
SQLQueryInsert.ExecSQL();
lista.Refresh;
LinkFillControlToField1.BindList.FillList;
except
on e: Exception do
begin
ShowMessage(e.Message);
end;
end;
end;
If you need some more code snippet, please ask!
Thanks in advance for any reply!
Try this method it works for me
procedure TData.InsertItem(someObject: TSomeObjectClass);
var
qry: TFDQuery;
begin
qry := CreateQry( 'insert into SomeObject(id, description, something)'+
' values (:id, :description, :something);', false);
qry.Params.ParamByName('id').AsInteger := someObject.id;
qry.Params.ParamByName('description').asstring := someObject.description;
qry.Params.ParamByName('something').asstring := someObject.something;
qry.Prepare;
qry.execsql;
qry.Free;
end;
I've put and object in the parameter but you can also put the data you want to insert seperatly
Related
I have an Access database table named ReceiptTable with the following field names: item name, buying price, selling price, goods total, cash, change. I am using an Adoquery and datasource to connect to the access database. When I want to update records to receiptTable, I use the following code to locate an item name from the database then update all the records with similar item name in the database with the values from edit box field values:
procedure TReceiptForm.BitBtn1Click(Sender: TObject);
begin
with ADOQuery1 do
ADOQuery1.Open;
ADOQuery1.Locate('item name',Edit1.Text,[]) ;
ADOQuery1.edit;
ADOQuery1.FieldValues['goods total']:=edit3.Text;
ADOQuery1.FieldValues['cash']:=edit4.Text;
ADOQuery1.FieldValues['change']:=edit5.Text;
ADOQuery1.Post;
end;
The problem I have is that only one row with the item name is updated but the other rows with similar item name are not updated. What code should I add above so that all the rows which have similar item names are updated with values from edit boxes?
This simple code answers your question:
procedure TReceiptForm.BitBtn1Click(Sender: TObject);
var
itemname, goodstotal, cash, change: string;
begin
// Execute query
try
ADOQuery1.Open;
except
on E: Exception do begin
ShowMessage(E.Message);
Exit;
end{on};
end{try};
// Values
itemname := Edit1.Text;
goodstotal := Edit3.Text;
cash := Edit4.Text;
change := Edit5.Text;
// Find first matching record, then go to the end of resultset.
try
ADOQuery1.DisableControls;
if ADOQuery1.Locate('item name', itemname, []) then begin
while not ADOQuery1.Eof do begin
if ADOQuery1.FieldByName('item name').AsString = itemname then begin
ADOQuery1.Edit;
ADOQuery1.FieldValues['goods total'] := goodstotal;
ADOQuery1.FieldValues['cash'] := cash;
ADOQuery1.FieldValues['change'] := change;
ADOQuery1.Post;
end{if};
ADOQuery1.Next;
end{while};
end{if};
finally
ADOQuery1.EnableControls;
end{try};
end;
This will work, but you can consider using one SQL statement for updating the table, or
if it is possible order your query by 'item name' and use this:
...
// Find first matching record, then update while next record matches too.
if ADOQuery1.Locate('item name', itemname, []) then begin
while (not ADOQuery1.Eof) and
(ADOQuery1.FieldByName('item name').AsString = itemname) do begin
ADOQuery1.Edit;
ADOQuery1.FieldValues['goods total'] := goodstotal;
ADOQuery1.FieldValues['cash'] := cash;
ADOQuery1.FieldValues['change'] := change;
ADOQuery1.Post;
ADOQuery1.Next;
end{while};
end{if};
...
Delphi 10 with Firemonkey and SQLite: After running the code below I want to get the ID of the last record inserted into an SQLite table. How do I get the last ID?
NOTE: The ID field of Table 1 is autoincrement.
var myQr: TFDQuery;
begin
myQr := TFDQuery.Create(Self);
with myQr do begin
SQL.Add('Insert into table1 values (:_id, :_name, :_dthr)');
Params.ParamByName('_id').ParamType := TParamType.ptInput;
Params.ParamByName('_id').DataType := TFieldType.ftInteger;
Params.ParamByName('_id').Value := null;
ParamByName('_name').AsString := 'name test';
ParamByName('_dthr').AsDateTime := Now;
ExecSQL;
end;
// How to get last ID? <<<<<<<<<<<<<=================
myQr.DisposeOf;
You could query last_insert_rowid if your ID column is declared as INTEGER PRIMARY KEY. In such case the column becomes alias for the ROWID. If that is your case, you can query it natively e.g. this way:
uses
FireDAC.Phys.SQLiteWrapper;
function GetLastInsertRowID(Connection: TFDConnection): Int64;
begin
Result := Int64((TObject(Connection.CliObj) as TSQLiteDatabase).LastInsertRowid);
end;
Or in common way by calling GetLastAutoGenValue method:
function GetLastInsertRowID(Connection: TFDConnection): Int64;
begin
Result := Int64(Connection.GetLastAutoGenValue(''));
end;
I'm working on porting a set of paradox tables to SQLite. In order to do so, I created a test application that simulates (somewhat) the current usage scenario: multiple users accessing the same DB file and performing simultaneous read and writes.
The application is very simple: it will start several threads that each create a connection, opens a table and will randomly read, update or insert inside the table.
Almost immediately, The application encounters a "database table locked" error. I have tried several things to attempt to work around it but nothing seems to work. What am I doing wrong ?
Here is the code internal to the threads:
procedure testDB(TargetFolder: string);
var
Conn: TFDConnection;
Table: TFDTable;
i: Integer;
begin
randomize;
Conn := TFDConnection.Create(nil);
try
Conn.DriverName := 'SQLite';
Conn.LoginPrompt := false;
Conn.Params.clear;
Conn.Params.Database := TPath.Combine(TargetFolder, 'testDB.sdb');
Conn.Params.Add('DriverID=SQLite');
// all this is the result of several attemp to fix the table locking error. none worked
Conn.Params.Add('LockingMode=Normal');
Conn.Params.Add('Synchronous=Normal');
Conn.UpdateOptions.UpdateMode := TUpdateMode.upWhereAll;
Conn.UpdateOptions.LockWait := True;
Conn.UpdateOptions.LockMode := TFDLockMode.lmPessimistic;
Conn.UpdateOptions.LockPoint := TFDLockPoint.lpImmediate;
Conn.UpdateOptions.AssignedValues := [uvLockMode,uvLockPoint,uvLockWait];
Conn.Open();
Conn.ExecSQL('CREATE TABLE IF NOT EXISTS ''test'' (''ID'' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,''data1'' TEXT NOT NULL,''data2'' INTEGER NOT NULL)');
Table := TFDTable.Create(nil);
try
table.Connection := Conn;
while True do
begin
case Trunc(Random(10)) of
0..3:
begin
table.Open('test');
try
if table.Locate('data1', 'name'+intToStr(Trunc(Random(10))),[TLocateOption.loCaseInsensitive]) then
begin
table.Edit;
table.FieldByName('data2').AsInteger := table.FieldByName('data2').AsInteger + 1;
table.Post;
end;
finally
table.close;
end;
end;
4..8:
begin
table.Open('test');
try
i := Trunc(Random(10));
if not table.Locate('data1', 'name'+ i.ToString,[TLocateOption.loCaseInsensitive]) then
begin
table.AppendRecord([null, 'name'+ i.ToString, 0]);
end;
finally
table.close;
end;
end
else
break;
end;
end;
finally
FreeAndNil(Table);
end;
finally
FreeAndNil(Conn);
end;
end;
Thanks to Victoria, I managed to find the right parameters.
Conn := TFDConnection.Create(nil);
try
Conn.DriverName := 'SQLite';
Conn.LoginPrompt := false;
Conn.Params.clear;
Conn.Params.Database := TPath.Combine(TargetFolder, 'testDB.sdb');
Conn.Params.Add('DriverID=SQLite');
Conn.Params.Add('SharedCache=False');
Conn.Params.Add('LockingMode=Normal');
Conn.Params.Add('Synchronous=Normal');
Conn.UpdateOptions.LockWait := True;
Conn.Open();
Thanks again
I need to run some SQL blocks to test them, is there an online app where I can insert the code and see what outcome it triggers?
Thanks a lot!
More specific question below:
<<block1>>
DECLARE
var NUMBER;
BEGIN
var := 3;
DBMS_OUTPUT.PUT_LINE(var);
<<block2>>
DECLARE
var NUMBER;
BEGIN
var := 200;
DBMS_OUTPUT.PUT_LINE(block1.var);
END block2;
DBMS_OUTPUT.PUT_LINE(var);
END block1;
Is the output:
3
3
200
or is it:
3
3
3
I read that the variable's value is the value received in the most recent block so is the second answer the good one? I'd love to test these online somewhere if there is a possibility.
Also, is <<block2>> really the correct way to name a block??
Later edit:
I tried this with SQL Fiddle, but I get a "Please build schema" error message:
Thank you very much, Dave! Any idea why this happens?
create table log_table
( message varchar2(200)
)
<<block1>>
DECLARE
var NUMBER;
BEGIN
var := 3;
insert into log_table(message) values (var)
select * from log_table
<<block2>>
DECLARE
var NUMBER;
BEGIN
var := 200;
insert into log_table(message) values (block1.var || ' 2nd')
select * from log_table
END block2;
insert into log_table(message) values (var || ' 3rd')
select * from log_table
END block1;
In answer to your three questions.
You can use SQL Fiddle with Oracle 11g R2: http://www.sqlfiddle.com/#!4. However, this does not allow you to use dbms_output. You will have to insert into / select from tables to see the results of your PL/SQL scripts.
The answer is 3 3 3. Once the inner block is END-ed the variables no longer exist/have scope. You cannot access them any further.
The block naming is correct, however, you aren't required to name blocks, they can be completely anonymous.
EDIT:
So after playing with SQL Fiddle a bit, it seems like it doesn't actually support named blocks (although I have an actual Oracle database to confirm what I said earlier).
You can, however, basically demonstrate the way variable scope works using stored procedures and inner procedures (which are incidentally two very important PL/SQL features).
Before I get to that, I noticed three issues with you code:
You need to terminate the insert statements with a semi-colon.
You need to commit the the transactions after the third insert.
In PL/SQL you can't simply do a select statement and get a result, you need to select into some variable. This would be a simple change, but because we can't use dbms_output to view the variable it doesn't help us. Instead do the inserts, then commit and afterwards select from the table.
In the left hand pane of SQL Fiddle set the query terminator to '//' then paste in the below and 'build schema':
create table log_table
( message varchar2(200)
)
//
create or replace procedure proc1 as
var NUMBER;
procedure proc2 as
var number;
begin
var := 200;
insert into log_table(message) values (proc1.var || ' 2nd');
end;
begin
var := 3;
insert into log_table(message) values (var || ' 1st');
proc2;
insert into log_table(message) values (var || ' 3rd');
commit;
end;
//
begin
proc1;
end;
//
Then in the right hand panel run this SQL:
select * from log_table
You can see that proc2.var has no scope outside of proc2. Furthermore, if you were to explicitly try to utilize proc2.var outside of proc2 you would raise an exception because it is out-of-scope.
I've been doing my university project and I've stumbled upon problem I cannot solve.
After declaring variable (a pointer to TButton) I cannot use it. I'll copy a part of my code to help show the problem.
So before the implementation I have
private
prevButton : ^TButton;
After that I use OnClick procedure with my buttons
procedure TForm2.MissingButtonClick(Sender : TObject);
var
b : TButton;
begin
b := Sender as TButton;
prevButton := #b;
showmessage(prevButton^.Caption);
end;
And caption is shown no problem. But then when I use my OnClick procedure and try to change labels caption I get access violation.
procedure TForm2.LabelClick(Sender : TObject);
var
l : TLabel;
begin
l := Sender as TLabel;
if prevButton = nil then
showmessage('nil');
if prevButton <> nil then begin
showmessage(prevButton^.Caption);
l.Caption := (prevButton^.Caption);
prevButton^.OnClick := #AlreadyClicked;
prevButton^.Free;
prevButton^ := nil;
prevButton := nil;
refreshLabels(words);
end;
end;
So here is the question, why can't I use my variable in this procedure if I could use it without problem second earlier in other procedure.
Cheers.
Your code is severely flawed in several places.
First, the initial declaration is incorrect. A variable of type TButton is already a pointer, so you don't have to dereference it:
private
prevButton: TButton;
You also don't have to dereference it when assigning to it or using it:
procedure TForm2.MissingButtonClick(Sender : TObject);
begin
prevButton := TButton(Sender);
showmessage(prevButton.Caption);
end;
I'm not sure what your LabelClick event is trying to accomplish. If you free prevButton, you also invalidate the original button to which you pointed it. In other words, if you assigned prevButton := Button1;, and then prevButton.Free;, you've also freed Button1, and I don't think that's your intent. You can safely assign nil to prevButton, but don't free it also:
prevButton := nil; // No longer points to existing object instance
If you want to change the OnClick of an existing button, don't jump through all of those hoops:
// Assign this to the button's OnClick in the Object Inspector
procedure TForm1.Button1FirstClick(Sender: TObject);
begin
ShowMessage('First time I was clicked');
Button1.OnClick := #Button1AfterClicked;
end;
// Create these two in the code editor, and declare it in the
// form declaration, but don't assign it to an event of the button
// in the Object Inspector
procedure TForm1.Button1AfterClick(Sender: TObject);
begin
ShowMessage('Second time clicked');
Button1.OnClick := #Button1MoreClicks;
end;
procedure TForm1.Button1MoreClicks(Sender: TObject);
begin
ShowMessage('Third and later clicks');
end;