问题
How would I define a column in PostgreSQL such that each value must be in a sequence, not the sequence you get when using type serial
but one such that a value 2 cannot be inserted unless there exists a value 1 already in the column?
回答1:
Theoretically, you could use a constraint that worked like this. (But it won't work in practice.)
- Count the rows.
- Evaluate
max(column) - min(column) + 1
. - Compare the results.
You'd probably have to insert one row before creating the CHECK constraint. If you didn't, max(column) would return NULL. With one row,
- Count the rows (1).
- Evaluate
max(column) - min(column) + 1
. (1 - 1 + 1 = 1) - Compare the results. (1 = 1)
With 10 rows . .
- Count the rows (10).
- Evaluate
max(column) - min(column) + 1
. (10 - 1 + 1 = 10) - Compare the results. (10 = 10)
It doesn't matter whether the sequence starts at 1; this way of checking will always show a gap if one exists. If you needed to guarantee that the gapless sequence started at 1, you could add that to the CHECK constraint.
As far as I know, there isn't any way to do this declaratively with any current dbms. To do it, you'd need support for CREATE ASSERTION
. (But I could be wrong.) In PostgreSQL, I think your only shot at this involves procedural code in multiple AFTER triggers.
I only have one table that needs to be gapless. It's a calendar table. We run a query once a night that does these calculations, and it lets me know whether I have a gap.
回答2:
I wrote a detailed example of a gapless sequence implementation using PL/PgSQL here.
The general idea is that you want a table to store the sequence values, and you use SELECT ... FOR UPDATE
followed by UPDATE
- or the shorthand UPDATE ... RETURNING
- to get values from it while locking the row until your transaction commits or rolls back.
回答3:
You write an on insert tigger
or a check constraint
. However, this will still allow to delete "1" afterwards and "2" stays in the table, you'll probably have to address this too.
来源:https://stackoverflow.com/questions/6988910/postgresql-column-values-must-be-in-a-sequence