Cannot update a record using SQLQuery, Update etc. lazarus / 16-Databases ---------------------------------------------------------------------- ranny · 2025-03-19 07:28 Hi, Many years ago I wrote a program that reads in an Access database and presented the user with some simple search options, it was written in Visual basic and the code is lost.  More recently I have tried to use Lazarus and I have struggled but in the last week or two I have made some progress. The principle is that it will read the database structure, present the records in a stringgrid, allow searches depending on the field type etc.  Nothing too difficult. However, whilst I can get that all working fairly well, I cannot seem to be able to update a record.  The way I wanted to do it was present eh record in a stringgrid, allow the fields to be edited, and then replace the whole record with the contents of the stringgrid. Here's what I tried:- //make ODBC connection     ODBCConnection1.Driver:= 'Microsoft Access Driver (*.mdb, *.accdb)';     ODBCConnection1.Params.Add('DBQ=.\id931.mdb');      // or specify full path to mdb file     ODBCConnection1.Params.Add('Locale Identifier=1031');     ODBCConnection1.Params.Add('ExtendedAnsiSQL=1');     ODBCConnection1.Params.Add('CHARSET=ansi');     ODBCConnection1.Connected:= True;     ODBCConnection1.KeepConnection:= True;     //transaction     SQLTransaction1.DataBase:= ODBCConnection1;     SQLTransaction1.Action:= caCommit;     SQLTransaction1.Active:= True; //not applied to ms access(false)     SQLQuery0.DataBase:= ODBCConnection1;     SQLQuery0.UsePrimaryKeyAsKey:= False;     DataSource0.DataSet:= SQLQuery0;        SQLQuery0.Update.Text:=     SQLQuery0.Open;    SQLQuery0.ApplyUpdates And then I get errors relating to databse not open or Operation cannot be performed on an inactive dataset. Ive tried a few things like SQLQuery0.ExecSQL an others and no joy. I would welcome any help on this as the project is nearly finished and this is the last thing to fix. Thanks in advance. ---------------------------------------------------------------------- Zvoni · 2025-03-19 07:44 SQLQuery-Object needs an assigned Transaction. Besides your Problem: If you have to rewrite everything (since your vb-code is lost), throw the Access-DB where it belongs: The rubbish- bin. Use SQLite ---------------------------------------------------------------------- ranny · 2025-03-19 08:04 Hi, Thanks for the comments.   I have:-     //transaction     SQLTransaction1.DataBase:= ODBCConnection1;     SQLTransaction1.Action:= caCommit;     SQLTransaction1.Active:= True; //not applied to ms access(false) Is this not what you suggest?  It doesnt appear to be associated  with my SQLQuery right enough. Sorry but I am not so good with this Databse stuff. I understand the comment on SQLite but all the databases exist and not necessarily under my control.... Thanks. ---------------------------------------------------------------------- CharlyTango · 2025-03-19 08:17 Without even having any possibility to test with Access, I can only make assumptions Check if the ODBC connection to Access ist stable and working. e.g. by showing some data in a TDBGrid and using a simple SQL Query like "SELECT x,y, from z WHERE anyclause ". Use an SQLQuery.Open for Queries that deliver results, otherwise use SQLQuery.ExexSQL Try an SQL Statement directly in Access first to check whether it is valid and works to avoid Syntax problems. Quote from: ranny on March 19, 2025, 08:28:19 am    SQLQuery0.Update.Text:=     SQLQuery0.Open;    SQLQuery0.ApplyUpdates This syntax is intended for use with data-sensitive input fields. For submitting a single UPDATE statement use Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SQLQuery0.SQL.Text:=;SQLQuery0.ExecSQL; Besides... avoid Access at all -- use SQLite instead ---------------------------------------------------------------------- TRon · 2025-03-19 08:20 Quote from: ranny on March 19, 2025, 09:04:14 amSorry but I am not so good with this Databse stuff. Example in wiki, basic use of SQLDB in documentation though in your example code the components are already created because done at design time (I assume) so you only have to follow how things are linked together. ---------------------------------------------------------------------- Zvoni · 2025-03-19 08:22 Quote from: ranny on March 19, 2025, 09:04:14 amHi, Thanks for the comments.   I have:-     //transaction     SQLTransaction1.DataBase:= ODBCConnection1;     SQLTransaction1.Action:= caCommit;     SQLTransaction1.Active:= True; //not applied to ms access(false) Is this not what you suggest?  It doesnt appear to be associated  with my SQLQuery right enough. Sorry but I am not so good with this Databse stuff. I understand the comment on SQLite but all the databases exist and not necessarily under my control.... Thanks. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SQLQuery0.DataBase:= ODBCConnection1;SQLQuery0.Transaction:=SQLTransaction1;  //<-- HERESQLQuery0.UsePrimaryKeyAsKey:= False;DataSource0.DataSet:= SQLQuery0; ---------------------------------------------------------------------- CharlyTango · 2025-03-19 08:32 Regarding transactions i would try it the other way round, but don't know whether it makes a difference: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ODBCConnection1.Transaction:= SQLTransaction1;  In my opinion this statement assigns a distinct transaction to all queries using ODBCConnection1. My applications use this syntax and they work. Maybe there is a possibility to use other transactions in certain query cascades as suggested by @zvoni I' dont know exactly which way ist the better one. Try both of them ;-) ---------------------------------------------------------------------- ranny · 2025-03-19 08:57 Thanks everyone for your advice and suggestions.  I carry out some edits and see what happens and report. Cheers. ---------------------------------------------------------------------- ranny · 2025-03-19 09:19 Ach, driving me nuts! Code is this:-     SQLQuery0.DataBase:= ODBCConnection1;     SQLQuery0.Transaction:=SQLTransaction1;;     SQLQuery0.UsePrimaryKeyAsKey:= False;     DataSource0.DataSet:= SQLQuery0;     SQLQuery0.ExecSQL;     SQLQuery0.UpdateSQL.Text:=fs;     SQLQuery0.Edit; I get this:- "Operation cannot be performed on an inactive dataset" at SQLQuery0.Edit If I use SQLQuery0.Post instead of SQLQuery0.Edit, I get this error "SQLQuery0: Operation not allowed, dataset "SQLQuery0" is not in an edit or insert state" Time for a coffee break.... ---------------------------------------------------------------------- Zvoni · 2025-03-19 09:35 Quote from: ranny on March 19, 2025, 10:19:06 amAch, driving me nuts! Code is this:-     SQLQuery0.DataBase:= ODBCConnection1;     SQLQuery0.Transaction:=SQLTransaction1;;     SQLQuery0.UsePrimaryKeyAsKey:= False;     DataSource0.DataSet:= SQLQuery0;     SQLQuery0.ExecSQL;     SQLQuery0.UpdateSQL.Text:=fs;     SQLQuery0.Edit; I get this:- "Operation cannot be performed on an inactive dataset" at SQLQuery0.Edit If I use SQLQuery0.Post instead of SQLQuery0.Edit, I get this error "SQLQuery0: Operation not allowed, dataset "SQLQuery0" is not in an edit or insert state" Time for a coffee break.... Spot the mistake...... Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     SQLQuery0.ExecSQL;    SQLQuery0.UpdateSQL.Text:=fs;    SQLQuery0.Edit;  ExecSQL, then changing the SQL-text, THEN goint to Edit-Mode.... *sigh* ---------------------------------------------------------------------- ranny · 2025-03-19 11:38 Apologies, I am trying to read up on this online and I find it a minefield. Zvoni, you say "ExecSQL, then changing the SQL-text, THEN goint to Edit-Mode.... *sigh*" when referencing:- SQLQuery0.ExecSQL; SQLQuery0.UpdateSQL.Text:=fs; SQLQuery0.Edit; With three lines as above there are six scenarios of which comes first, second and third, I tried them all and they all fail on SQLQuery0.edit no matter where it is placed. Something adrift elsewhere. I think I will park this project for a while and do some reading up. Thanks for your input. ---------------------------------------------------------------------- cdbc · 2025-03-19 11:49 Hi Try this instead:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i SQLQuery0.Close;SQLQuery0.SQL.Text:=fs;SQLQuery0.ExecSQL;That just might work... Regards Benny ---------------------------------------------------------------------- 1HuntnMan · 2025-03-19 13:42 Zvoni recommended what I am in the process of doing.  I am currently finishing converting an app that was written for a TDbf database. Chunk the MS-Access and use SQLite3. I have all my source so once you get the hang of properly declaring your database, creating a transaction, connecting to the database and then opening, your in business. I'm in a learning process but it's working. Here's an example of what I learned, mostly from TRon but others. If you do decide to move to SQLite3 as Zvoni recommended and what I learned from TRon, et. al., create a datamodule or just a Form and opening it up in your main Program file before anything else(Application.CreateForm(DB or Form)). Then put a TSQLite3Connection, TSQLQuery and TSQLTransaction on the DM or Form. Then in the DM/Form Connect to your database, then create a transaction pointing to your connect, point to the database by assigning your connect to your transaction and then open it and point to the database and the transaction. Here's the way I did from learning from TRon in my datamodule. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TDmPMSDataBase.DataModuleCreate(Sender: TObject);begin  ConnectPMSDB.DatabaseName:= SysUtils.ExtractFilePath(ParamStr(0)) + 'PMSDB.sqlite';  //-> Create a transactions...  TransPMSDB:= TSQLTransaction.Create(ConnectPMSDB);  //-> Point to the database instance...  TransPMSDB.Database:= ConnectPMSDB;  //-> Open the PMS database...  ConnectPMSDB.Open;  //-> Point to the database and transaction...  QueryPMSDB.Database:= ConnectPMSDB;  QueryPMSDB.Transaction:= TransPMSDB;end;  Then as your writing code you just use SQL, this is snippet from just my Clients Management part of my application: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TFrmClientsMgt.FormShow(Sender: TObject);begin  //-> Set the SQL select statement...  DmPMSDataBase.QueryPMSDB.SQL.Text:= 'SELECT * FROM CLIENTS';  //-> Now use the standard TDataset methods...  DmPMSDataBase.QueryPMSDB.Open;  BitBtnSave.Enabled:= False;  BitBtnCancel.Enabled:= False; Hope this helps but this is SQLite3, not MSAccess. ---------------------------------------------------------------------- 1HuntnMan · 2025-03-19 19:35 SQLite is the most used database engine in the world... https://www.sqlite.org/mostdeployed.html ---------------------------------------------------------------------- egsuh · 2025-03-20 01:57 Simply from curiosity... Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TDmPMSDataBase.DataModuleCreate(Sender: TObject);begin  ConnectPMSDB.DatabaseName:= SysUtils.ExtractFilePath(ParamStr(0)) + 'PMSDB.sqlite';   TransPMSDB:= TSQLTransaction.Create(ConnectPMSDB); // Question here    TransPMSDB.Database:= ConnectPMSDB;  ConnectPMSDB.Open;   QueryPMSDB.Database:= ConnectPMSDB;  QueryPMSDB.Transaction:= TransPMSDB;  // comment: this is not necessary. end; Question: It seems that you have dropped a TSQLite3connection component and TSQLQuery component from component pallette, but why not TSQLTransaction? Why do you create it here? Comment: When you assign database to a query, the default transaction is used. You don't to have to assign it again, unless you are going to use different transaction. Your way has no problem. I'm asking simply from curiosity. ---------------------------------------------------------------------- Zvoni · 2025-03-20 13:39 Quote from: egsuh on March 20, 2025, 02:57:57 amComment: When you assign database to a query, the default transaction is used. You don't to have to assign it again, unless you are going to use different transaction. Your way has no problem. I'm asking simply from curiosity. Not that i know of. I always had to connect the 3 (or more) Objects as described in Wiki/Documentation: Create Connection-Object Create Transaction-Object (or as many as you need) Assign Transaction-Object to Transaction-Property of Connection-Object (only one Transaction per Connection?) Assign Connection-Object to Database-Property of Transaction(s) Create Query-Object(s) Assign Transaction-Object to Transaction-Property of Query Assign Connection-Object to Database-Property of Query Open Connection Activate Transaction(s) Open Query(s) EDIT: I just looked into the Source-Code of sqlite3conn: there is no "Default"-Transaction-Object for sqlite3connection, only the Inherited Transaction-Object of its Ancestor TSQLconnection. and in sqldb (TSQLConnection) i found this snippet Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TSQLConnection.GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings); var qry : TCustomSQLQuery; begin  if not assigned(Transaction) then    DatabaseError(SErrConnTransactionnSet); If transaction is not Assigned return what?? ---------------------------------------------------------------------- egsuh · 2025-03-22 00:10 QuoteEDIT: I just looked into the Source-Code of sqlite3conn: there is no "Default"-Transaction-Object for sqlite3connection, only the Inherited Transaction-Object of its Ancestor TSQLconnection. and in sqldb (TSQLConnection) i found this snippet Hmmm..  I'm more accustomed to using components from component palletes. Generally I drop one database, one transaction, and sqlquery components on Datamodule, and set Transaction's database to Database, and then SQLQuery's database to database.  Then at the object inspector of sqlquery, transaction is set automatically. Not sure when programmed. I love easy life ^^