#1 2022-10-20 18:32:58

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

memberexists does not help

var b:boolean;
      o:TOrmamyclass;
......
 if srv.Orm.MemberExists(TOrmamyclass,o.IDValue) then b:=srv.Orm.Update(o) else b:=srv.Orm.Add(o,true,true)=o.IDValue;

The above does not work all the times, I am getting:

Exception: 20221020 16294225  " EXC   EZSQLException {Message:"SQL Error: Duplicate entry '1611284410' for key 'PRIMARY' \r\nCode: 1062 SQL: insert into amyclass (bid,xml,stat) values (?,?,?)"} [Pool7-TEpresslave] at 0235e59a ZDbcMySql.pas TZMySQLConnection.HandleErrorOrWarning (1271)  ZDbcMySql.pas TZMySQLConnection.HandleErrorOrWarning (1271) ZDbcMySqlStatement.pas TZAbstractMySQLPreparedStatement.ExecuteUpdatePrepared (1150) mormot.db.sql.zeos.pas TSqlDBZeosStatement.ExecutePrepared (1204) mormot.orm.sql.pas TRestStorageExternal.ExecuteFromJson (2096) mormot.orm.sql.pas TRestStorageExternal.EngineAdd (1249) mormot.orm.rest.pas TRestOrm.Add (1725) .........

There are not many threads that try to write the same thing
Without ORM I used to have a REPLACE sql command. Now what to do?
After the above, everything goes out of control with "Commands out of sync" and that generally happens if such an error (duplicate primary key or field out of range) happens
Delphi 11.2 win32

Offline

#2 2022-10-21 07:23:55

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,655
Website

Re: memberexists does not help

You could either call srv.Orm.WriteLock/WriteUnlock or use a batch with the boInsertOrReplace option.

Offline

#3 2022-10-21 07:30:55

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

Re: memberexists does not help

Thank you @ab. Please try to have a replace function as we have  add/update for ORM

An other question:
If I use a batch, how can I add to the batch a sql command for multiple rows like the following:

update table set act=0

Thank you in advance

Offline

#4 2022-10-21 07:35:28

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

Re: memberexists does not help

Reading the following response from overflow:


REPLACE INTO table(column_list) VALUES(value_list);

is a shorter form of

INSERT OR REPLACE INTO table(column_list) VALUES(value_list);

For REPLACE to execute correctly your table structure must have unique rows, whether a simple primary key or a unique index.

REPLACE deletes, then INSERTs the record and will cause an INSERT Trigger to execute if you have them setup. If you have a trigger on INSERT, you may encounter issues.

This is a work around.. not checked the speed..

INSERT OR IGNORE INTO table (column_list) VALUES(value_list);

followed by

UPDATE table SET field=value,field2=value WHERE uniqueid='uniquevalue'

This method allows a replace to occur without causing a trigger.

Probably an insertOrIgnore (or an extra boolean flag in add to add 'or ignore') is better for this case and it is supported by sqlite

Last edited by dcoun (2022-10-21 07:38:35)

Offline

#5 2022-10-21 08:13:07

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,655
Website

Re: memberexists does not help

The batch does not support such full update.
This is a statement which may be very slow on a big database. So the idea is to use IRestOrm.UpdateField with WriteLock/WriteUnLock if you want to do something else atomically at the same time.

I will look into adding IRestOrm.Replace but it should work also on databases which have no REPLACE process.
There is already IRestOrm.AddOrUpdate() but it generates a new ID - which is not what you need.

Offline

#6 2022-10-21 08:14:54

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

Re: memberexists does not help

Thank you a lot @ab
check also the above discussion
Probably adding ignore to INSERT is a better approach

Offline

#7 2022-10-21 09:21:33

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

Re: memberexists does not help

From a small search, INSERT IGNORE is supported by SQLITE, postgres, Oracle, mysql, mariadb,firebird
SQLITE,mysql : INSERT IGNORE
Oracle: INSERT .... IGNORE_ROW_ON_DUPKEY_INDEX
Firebird: UPDATE OR INSERT

For Oracle there is enough info:
https://blogs.oracle.com/sql/post/how-t … e-database
http://guyharrison.squarespace.com/blog … -hint.html (old article)

Offline

#8 2022-10-21 10:38:55

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,655
Website

Re: memberexists does not help

Note that insert/or/ignore is not exactly the same as update/or/insert.

Take a look at EncodeInsertPrefix() in mormot.db.core.pas.
We did not include Oracle yet because it is very complicated to get it working properly. As often with Oracle.
And PostgreSQL also expect a complex syntax with the column names to ignore, as On CONFLICT(column1, ....) DO NOTHING;.

Offline

#9 2022-10-21 10:53:32

dcoun
Member
From: Crete, Greece
Registered: 2020-02-18
Posts: 430

Re: memberexists does not help

ab wrote:

Note that insert/or/ignore is not exactly the same as update/or/insert.

Take a look at EncodeInsertPrefix() in mormot.db.core.pas.
We did not include Oracle yet because it is very complicated to get it working properly. As often with Oracle.
And PostgreSQL also expect a complex syntax with the column names to ignore, as On CONFLICT(column1, ....) DO NOTHING;.

I am not familiar with Oracle and Firebird
Firebird,  Oracle, Postgres do not have an 'INSERT [OR] IGNORE' dialect

For Oracle I have included the info

For firebird >2.1 is just a little more complex (you have to provide the unique indexes) as described here:
https://firebirdsql.org/refdocs/langref … nsert.html

For postgres  >9.5 nearly the same with firebird
INSERT INTO table(column1, column2, ...)
VALUES
  (value1, value2, ....),
  (value1, value2, ....)
On CONFLICT[(column1, ....)] DO NOTHING;
https://www.postgresql.org/docs/10/sql-insert.html

Last edited by dcoun (2022-10-21 10:56:39)

Offline

Board footer

Powered by FluxBB