Here’s my toy setup. I have 3 tables. One table is a guest list (last name, first name, whatever), a food list (beans, paste, rice, veggies) and an order list (guest id, food id). The order list is the one that interests me. I want to constrain it for the following condition.
Guests must have 3 orders.
A guest can have a null order.
No order per guest can be the same UNLESS that order is null.
So the order table would look like the following (with strings instead of fk ids):
steve, beans
steve, rice
steve, veggies
joey, rice
joey, beans
joey, <null>
sarah, rice
sarah, <null>
sarah, <null>
sam, <null>
sam, <null>
sam, <null>
Apparently Sam doesn’t like food … But that would be a valid table. Every user has 3 entries, and no user has duplicates (no double beans for you!).
Things I have tried
create table order (
guest_uid FK,
food_uid FK,
CONSTRAINT order_unique UNIQUE (guest_uid, food_uid)
)
This works fine for verifying no double beans, but the double/triple null won’t fly. I was hoping the oracle unique null would apply here, but I guess not (unique constraint order_unique violated).
I tried a few other check constraints but I can’t figure out a way to specify the uniqueness across rows without doing a subquery (which is not allowed, of course). Any thoughts? Thanks
ps. If the only valid answer is “use PL/SQL or triggers,” I’ll make sure to mark that the correct answer.
You can use a function-based index to enforce the uniqueness across rows (note that I called the table
guest_foodsinceorderis a reserved wordThat will allow you to have as many rows with a
NULLfood_uidfor any particularguest_uidwhile disallowing duplicate non-NULL values.The requirement that every guest has exactly three rows in the
guest_foodtable is not something you can enforce with a constraint. You could potentially create a materialized view that does a fast refresh on commit that stores a count of the number of rows perguest_uidand add a constraint that throws an error if that count is anything other than 3. But that’s generally a rather unusual thing to want to enforce so it would tend to make me suspect that the data model was a bit off.