Is Access's AutoNumber (Increment) guaranteed

2019-02-20 19:05发布

问题:

For a particular table, I have my ID field set to AutoNumber (Increment). If I add 5 rows to this table in quick succession, is each guaranteed to have a larger ID than the last? For instance, does autonumbering ever restart from 1 if some earlier values have been deleted?

回答1:

The only time I have ever had trouble with Access autonumbers is when, in error, I set the value of an autonumber key field to a number lower than the current maximum using an append query. Gaps had been created in the numbering by record deletions. Access allows you to force a value into an autonumber field, and sometimes (not always, and I don't know why) the autonumbering gets reset to the lower number. Eventually, as records were added, I ran into 'duplicate key' errors. Other than this, I've never had trouble in many years.

There are a couple of answers to this question which talk about an increment value. As far as I know, an Access autonumber field can only be set to 'Increment' (by 1) or 'Random', and there is no way of setting a numeric increment other than 1. If I am wrong about this, please enlighten me.



回答2:

Sadly, even Microsoft's applications are not infallible. But that's the way it's intended to work, and I've not seen it fail; nor heard of it fail short of intential or accidental subversion.

Just don't expect it to have a row for every integer value, though. In addition to deleted rows, it will use up numbers for append operations that fail.



回答3:

The statement "If some records are deleted AND the database is compacted the next identity is reset to the lowest used number + 1" is incorrect. This happened in Jet 3.5 used in Access 97 but not Jet 4.0 used in Access 2000.



回答4:

David W. Fenton wrote: "The Jet Autonumber field is not an identity field. It is only a long integer field with a special default value. That default value can be INCREMENT or RANDOM, but as it is only a default value, you can append any long integer value to the field as long as it doesn't violate the index."

This is a bit confused. ACE/Jet SQL syntax has an IDENTITY keyword (COUNTER, AUTOINCREMENT) but no AUTONUMBER keyword. Clearly an ACE/Jet IDENTITY is an IDENTITY!

But what I want to address here (too long for a comment) is the misstatement about it being "only a long integer field with a special default value".

Consider this ACE/Jet SQL DDL (ANSI-92 Query Mode syntax):

CREATE TABLE Test2_IDENTITY
(
   ID_identity_1 IDENTITY NOT NULL, 
   ID_identity_2 IDENTITY NOT NULL, 
   data_column INTEGER
);

When executed, it fails with the message, "Resultant table not allowed to have more than one AutoNumber field". So clearly there is something other than just a "special default value" going on here.

The IDENTITY keyword is creates an autonumber (for want of a better term) with an incrementing algorithm to generate values. IDENTITY cannot be used to create an autonumber with a random algorithm or a GUID (replication ID) flavour of autonumber. For these other cases you do indeed need to use a "special default value" e.g.

CREATE TABLE TestAutonumbers 
(
   ID_identity IDENTITY NOT NULL, 
   ID_random INTEGER DEFAULT GenUniqueID() NOT NULL, 
   ID_guid UNIQUEIDENTIFIER DEFAULT GenGUID() NOT NULL, 
   data_col INTEGER
);

If you use a technology such as ADOX to examine this table's properties (information schema) you'll find that only the column created with the IDENTITY keyword has the Autoincrement property set to true, and this column's COLUMN_HASDEFAULT is false and COLUMN_DEFAULT is null. So if an IDENTITY column does have a "special default value" then the engine isn't telling.

Unlike IDENTITY, with these other flavours of autonumber there is no explicit one per table restriction e.g. this works fine:

CREATE TABLE Test2_Autonumbers
(
   ID_random_1 INTEGER DEFAULT GenUniqueID() NOT NULL, 
   ID_random_2 INTEGER DEFAULT GenUniqueID() NOT NULL, 
   ID_guid_1 UNIQUEIDENTIFIER DEFAULT GenGUID() NOT NULL, 
   ID_guid_2 UNIQUEIDENTIFIER DEFAULT GenGUID() NOT NULL, 
   data_col INTEGER
);

Something I do not know is whether there exists a "special default value" equivalent to GenUniqueID() and GenGUID() to create an auto-increment column using DEFAULT and without using the IDENTITY keyword (or its synonyms). If anyone knows one way or the other, please let me know.

BTW the abovementioned error message suggests I was wrong about 'Autonumber' being an Access term. Seems at the ACE/Jet engine level 'Autonumber' is a non-keyword synonym for IDENTITY (i.e. auto-increment flavour autonumber) but not a synonym for other flavours of autonumber.



回答5:

I have a table that was formerly used in a replicated database. Some of the autonumbers are negative, and some are very large. This is normal for a replicated table, so you cannot be certain that an autonumber will be larger than the previous number, it could be negative.



回答6:

The Jet Autonumber field is not an identity field. It is only a long integer field with a special default value. That default value can be INCREMENT or RANDOM, but as it is only a default value, you can append any long integer value to the field as long as it doesn't violate the index.

An incrementing Autonumber will never revert to 1 except if you've deleted all records and compacted, or in the event of a corrupt seed value. The latter happened frequently in the early versions of Jet 4 (before service pack 6), where the seed value would get reset, and this would lead to all sorts of problems, including corrupted PK indexes. Fortunately, that eventually got fixed, and because Jet is a Windows component, hardly any computer out there is going to have anything less than Jet 4 service pack 8.

As onedaywhen said, you can get negative values if the incrementing Autonumber exceeds the maximum positive value for long integer, but this would indicate to me that you probably have enough records in your table that you need a different database engine, or you're improperly treating your table as a temp table (i.e., appending and deleting large numbers of records).

As others have also said, uniqueness is not controlled by the Autonumber data type, but by the index. If you created a non-unique index, you could append duplicate values. I can't imagine why you'd want an Autonumber field with duplicate values, but the point is that you can do it if you don't add a unique index. Since most Autonumber fields are used as surrogate primary key, they will have the unique PK index, and the data table will be written in PK order (clustered). In regard to uniqueness, if you are using an Autonumber as a surrogate PK and you have any natural keys in the table that should be unique (and can be unique, i.e., no Nulls allowed), you should also have a unique index on the natural key field(s) (a single field or a compound index).



回答7:

First, your IDENTITY (Autonumber in Access) column must be INTEGER (Long Integer in Access) as opposed to UNIQUEIDENTIFIER (Replication ID in Access), must use the increment algorithm as opposed to the random algorithm for generating new values and assuming your seed and increment values respectively are both the default value 1, then if you delete all the rows in the table and compact the database then the IDENITTY column should be reseeded at 1. If it doesn't then you may need to install a Jet service pack (http://support.microsoft.com/kb/287756).

Note that when the maximum positive value for INTEGER (Long Integer in Access) would be exceeded by the next auto-generated value then it will 'wrap' into the negative INTEGER range and will continue to cycle through the positive and negative ranges, generating duplicate values where necessary (unless the column is additionally covered by a unique constraint). Indeed, if the increment value is large enough you can guarantee that the values will alternate between being greater than and less than the previous auto-generated value e.g. (ACE/Jet ANSI-92 Query Mode syntax):

CREATE TABLE Test 
(
   ID INTEGER IDENTITY (0, 2147483647), 
   data_col INTEGER NOT NULL UNIQUE
)
;
INSERT INTO Test (data_col) VALUES (1)
;
INSERT INTO Test (data_col) VALUES (2)
;
INSERT INTO Test (data_col) VALUES (3)
;
INSERT INTO Test (data_col) VALUES (4)
;
INSERT INTO Test (data_col) VALUES (5)
;
INSERT INTO Test (data_col) VALUES (6)
;
INSERT INTO Test (data_col) VALUES (7)
;
INSERT INTO Test (data_col) VALUES (8)
;

The auto-generated values are 0, 2147483647, -2, 2147483645, -4, 2147483643, -6, 2147483641, etc.



回答8:

My answer is 3 strings of VBA code!

Set db = CurrentDb
Set tbl = db.TableDefs("your_tbl")
Set current_index = tbl.Indexes.Item("PrimaryKey").DistinctCount


回答9:

If some records are deleted AND the database is compacted the next identity is reset to the lowest used number + 1 - if the table is emptied the next identity is set back to 1 after the compact.