> In an SQL statement that inserts, deletes, or updates many rows,
> SQLite as well as MySQL InnoDB checks UNIQUE and FOREIGN KEY
> constraints row-by-row.
> According to the SQL standard, the default behavior should be deferred
> checking.
> http://stackoverflow.com/questions/7703196/sqlite-increment-unique-integer-
> field

The behaviour is correct.  Consider the case where num were the referenced in a 
foreign key constraint and updates were cascading, any method of achieving the 
update other than updating through a cursor (including allowing deferral of 
integrity checking until commit time) which violates the unique constraint in 
an interim update would result in an inconsistent database (loss of integrity), 
for example, if a row with num = n+1 were updated following the update of a row 
with num = n, for any n.  There are ways to "re-phrase" the update to avoid 
this, but it requires domain knowledge and therefore the engine cannot do it 
for you.  Nor should it.

Create table numbers (num int unique);
Create table others (a int, num int unique references numbers (num) on update 
cascade);
Insert into numbers values (1), (2), (3), (4);
Insert into others values (1,1), (2,2), (3,3), (4,4);

Then any interim update to num which violated the unique constraint would 
result in integrity loss and the update should fail irrespective of row order.  
And you ought not depend on row order unless explicitly stated in the SQL 
statement.  Turning off constraint checking (or deferring it until commit time) 
places the consequence of "not knowing what you are doing" directly in the 
hands of the programmer (where it belongs).  If you know enough about the 
database to disable the integrity checking, you ought to be struck with the 
consequences (if any).

The only way to do the update without such side-effects is to ensure that the 
update does not have any interim (row by row) violations of integrity.

In other engines you would use:

update numbers set num = num + 1 from numbers order by num desc;

To control the row processing order by performing the update though "current of 
cursor", which would always obtains the correct result every time.

Perhaps a useful enhancement would be to permit an update to use from and order 
by clauses thus allowing such an update to be expressed directly.  Effectively, 
such an update would become a "select" where instead of returning rows, the 
return a row would be replaced with the update operation...

Some refer to this as an updateable view.  It really isn't.  It is still an 
update of "current of cursor", the update just takes place for each valid 
result row in a result set by allowing additional tables to be joined into the 
cursor, rather than restricting the cursor to only the single updated table.

You can achieve this presently by creating a view with the correct ordering, 
and then an update trigger for the num column on the view which updates the 
underlying table, then performing the update against the view:

Create table numbers (num int unique);
Create table others (a int, num int unique references numbers (num) on update 
cascade);
Insert into numbers values (1), (2), (3), (4);
Insert into others values (1,1), (2,2), (3,3), (4,4);
Create view updatenumbers
as 
 select num from numbers order by num desc;
Create trigger updnum instead of update of num on updatenumbers 
begin 
 update numbers set num = new.num where num=old.num; 
end;

update updatenumbers set num = num + 1;

sqlite> select * from numbers; select * from others;
2
3
4
5
1|2
2|3
3|4
4|5


---
()  ascii ribbon campaign against html e-mail
/\  www.asciiribbon.org



_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to