sashaDG said:
The case when a row is deleted n -> the table is updated (should shift n + 1 rows and remove the void)
It's more precise to talk of records, also in terms of how the VFP language refers to reccount, recno, etc.
But you can assume row and record are used as synonyms in the following, too:
That's not what you do. It's not a bad idea to reuse deleted rows for new rows, but there's a very strong reason DBFs were not designed to automatically shift rows up, when one is deleted. Assume a table has grown to MBs, perhaps even 100s of MBs. Deleting one row somewhere in the middle of the file, with the goal of keeping the records in their order, you actually need to copy the file part after the deleted row up recsize() bytes, which isn't a fast file operation. That's why there is a deletion flag in each record you just mark a record as deleted and don't remove it physically from the DBF file.
The other option is to fill the gap, but not in the fashion to move all further records one up, instead just move the last undeleted record to the gap record and delete it. In each further step, obviously look for the last
undeleted record to swap with a deleted. To keep the chronological order, which isn't the physical order anymore, the only reliable thing is a datetime field. Nothing else.
You asked in detail:
sashaDG said:
Is it possible to do this without a primary key?
There is no need. I don't know why you thought it, maybe you only thought about an autoincrement integer. This actually makes it impossible, as the autoincrementing field becomes readonly, only written once when a new record is generated. If you thought about the id number keeping track of the chronoloigcal order, that's right, with a primary key index on a sequential integer column the records are in numerical order, even if you do swaps to remove gaps.
It's not the natural thing to do anyway, the common sense solution is to not be picky about it, and PACK your tables in a maintenance over night from time to time. There is SET DELETED ON, to suppress any record marked as deleted from anything, from SQL or non-SQL operations, so that's enabling to work with DBFs as if the deleted records in them actually are not part of the file. There are only very few things this affects, there is no way to alternative between two colors by just using odd/even of the recno. But once you use view or CA, which both query data of a DBF into a cursor, at start you always have no deleted records in them and you
can use modulo 2 of the record number to alternate between 0 and 1, for example. Or as simpler aspect, you have reccount records numbered from 1 to reccount in the view. Which isn't the full table, usually, but just the section of data needed in a form, like one order to process order fulfillment of it, or a list of orders not fully processed - in contrast to all orders. There always is a way to only get the data you actually need instead of all.
Just take this away from all of it:
1. Your requirement isn't necessary
2. You work with SET DELETED ON - remember it means to turn ON the feature of taking the deletion flag into account to suppress access to deleted rows.
3. You PACK DBFs as maintenance.
And by the way, this isn't just a thing about DBFs, it's a common scheme to actually allow fragmentation of data files also in server databases, and to not keep the database size as compact as necessary. This wasn't even a concern back in the days dbase started andd hdd space was expensive. Performance had a bigger impact on the usability of data, and still has, than saving as much space as you could possibly do. You also don't shrink server databases just because you deleted a record in a table. It would be just a waste of time with no benefit.
By the way, even if ou do what's possible with moving deleted rows to the end of a file. The reorganization of index node recnos you trigger by this doen't make the tree structure of an index optimal, this happens when you reindex because you pack more optimal, so a goal of avoiding PACK is actually not desirable as you then don't reorganize indexes from time to time, but instead grow them into something thaat eventually becomes less effective.
Any concerrn you have with gaps is better addressed individually. Like alterating background coloring is easily done in a report when you use a report variable that counts and use modulo 2 of it instead of the recno of the report data. That's universally applicable to any report without any complicated stunt man actions to keep a DBF file "tidy".
Chriss