OK, I’m making user database in PostgresQL, which I have been using for a month or two, but am not very familiar with. Currently, each user that registers is auto-assigned a unique ID via a PostgresQL sequence. This has always been the practice and has always worked fine, HOWEVER…
I have a request from the client to be able to manually enter users certain IDs. I’m not expecting more than 300 users, so I was reserving IDs 500-600 for manually-entered IDs. (If they register online, they get the auto-incremented number, most likely not over 300. If they need a manual ID, they are given a pre-determined ID between 500 and 600 only.) Yes, I am 99.9999% sure that there will not be more than 300 ‘auto-id’ users.
I would really like to be able to give any manual ID I’d like and then if they register online and the ID is already taken, they get the next available ID. I realize this defeats the purpose of the sequence, however, I’m not sure what my other option is. I only have a certain number of IDs I can give out, so I’d rather not just ‘max+1’, if possible – I’d like to “fill in the gaps”. I’m fairly sure the answer lies somewhere in updating the sequence when an ID is manually entered, but that sounds like a bad idea, not sure why.
If it’s not a great idea, just say – “Hey, you’re a moron. Who put you in charge of a database?” and we’ll all go about our day. Thanks for your time.
I’d probably
DROPthe sequence completely andALTER TABLEto remove the default from the column. Then, duringINSERT, I’d write something like:This has bad concurrency. Exactly one transaction can be inserting a user at any given moment. Given the volumes you’re working with that should be perfectly fine so long as you keep your transactions short.
Consider adding a new field that’s used as a public display identifier, separate to the database’s internal primary key. Use this field for display for the customer’s purposes. Let them put whatever they want in it, just declare it
UNIQUEas part of a suitable unique key.If you do that you can keep the underlying number assignment using a sequence the same, so you don’t have to change how you refer to the users elsewhere in the DB. You don’t have to change how any of the rest of the app refers to users internally. When displaying a user identifier, just look up the “user number” for display and use that. When the user enters a user number, look up the primary key of the matching row. The user number is only needed for input/output as an identifier for the end user, it doesn’t get referenced in the rest of the database.
This is why database/app design wisdom stresses that you should generally not expose generated keys to the user. Eventually, if they can see them they’ll inevitably want to be able to change them with “fun” results. Much easier to give them their own public identifier to play with. If they suddenly decide it should be alphanumeric, but only on Tuesdays with a full moon – that’s OK, you can do that.
Once you’ve split the “display identifier” and “unique internal row key” into separate things, you’re free to do whatever you want with the display identifier, including easily letting them change it.