Here's what I would do. I hope I did understand your question correctly. It's a workaround and perhaps not very elegant:
- create a random field, and then an AUTO_INCREMENT field ("ID") as the single field of a primary key, order by RND etc
- create a temporary table with MIN(ID) for each combination of Col1/2 (first, but randomly):
SELECT
MIN(ID) AS MIN_ID, Col1, Col2
FROM
table
GROUP BY
Col1, Col2
- add a second INT field to be the first_index
- update the table and set first_index to be the difference between the minimum value and the running value of the autoincremented field:
UPDATE
table t, temp_table tmp
SET
t.first_index = (t.ID - tmp.MIN_ID) + 1
WHERE
t.Col1=tmp.Col1 AND t.Col2=tmp.Col2
- optionally remove the random and ID field, and add a new PK with the three fields Col1/Col2/first_index (auto incremented) for following inserts
I'll answer obliquely...
The natural key is always the natural key and should be enforced with a unique constraint or index. This is the "primary key" that flows from your modelling phase.
The choice of an auto-number/identity surrogate key matters at implementation phase because there are good and bad choices for your clustered index (example: SQL Server, Sybase, MySQL InnoDB, Oracle IOT).
That is, primary key is orthogonal to your clustered index: don't confuse the two issues
I'd suggest using a contrived key adds no value over using an auto-number/identity column in this respect. You lose data from the natural key, probably won't be unique, is just as opaque.
FWIW, I use surrogate keys and composite keys when I need too:
- Some natural keys are useful in their own right: ISO currency and country codes
- A table with no secondary (non-clustered) indexes and no child table doesn't benefit from a surrogate key
- If you have parent-child-grandchild, then I usually need to join parent-grandchild: with composite keys I can do so directly. Simpler JOINs, simpler indexes
Note: this assumes that every table requires a clustered index
Related on dba.se: SQL Server Primary key / clustered index design decision
Best Answer
In Informix, a SERIAL column is a 4-byte signed integer with some auto-increment properties.
If you insert the value 0 into a SERIAL column, or fail to provide a value for the serial column, the next number in ascending order will automatically be assigned for this row. In a programming language such as ESQL/C, you can retrieve the value inserted from the SQLCA record. There are also, I think, functions to retrieve the last serial value inserted. If you insert a value into a SERIAL column, that is the value that will be use. Clearly, if there is a unique constraint on the column (there isn't one automatically, though the DB-Access Schema Editor will add one for you) and you insert a duplicate record, then the insertion will fail. If there is no unique constraint, it will succeed. If the newly inserted value, N, is larger than any previously inserted, then the internal counter will be incremented so that the next row inserted with 0 will be assigned N+1.
The second part of the question asks:
What will happen when the SERIAL value reaches the maximum?
This leads to an answer for the first part of the question:
Is there any method to initialize the serial again to zero?
There is. You insert 231-1 into the serial column. The next row you insert will be assigned the value 1 (not zero). It will keep going from there. Note, however, that if there are many values from the first cycle still in the table, this will cause problems; insertions will fail because the value is already in use.
Once upon a very long time ago, in versions that are, I believe, safely out of service (we're talking early or mid 1990s here), you had to insert 231-2 and then 2 rows with zeroes. If you inserted 231-1 directly, the system got confused and jammed itself.
1 You can get a row where there is a zero in the SERIAL column, but only through a back-door cheat. You have to have the column as a plain INTEGER column when you insert the row; then you alter the table so the column is a SERIAL column. So, as I said, you can't insert a row with zero in the SERIAL column, but you can find a row with zero in the SERIAL column if someone is devious enough.
Demonstration
SQL commands prefixed with a
+
and a blank; output from the DBMS without that prefix. Note that this table was created without a unique constraint or primary key on the serial column; this is not what I'd normally do.I formally checked that
ALTER ... SERIAL(0)
produces the same result asALTER ... SERIAL(1)
.