I have a ‘users’ table with two columns, ’email’ and ‘new_email’. I need:
-
A case-insensitive uniqueness constraint covering both columns – i.e., if “Bob@Example.com” appears in one row’s ’email’ column, then inserting “bob@example.com” into another row’s (or even the same row’s) ‘new_email’ column should fail.
-
Fast case-insensitive searching for a given email address in either the ’email’ or ‘new_email’ fields – i.e. find the row where the new_email OR email is “Bob@example.com”, case-insensitive.
I know that I could do this more easily by creating a related ’emails’ table, but I’m expecting to be looking up users in this table (by primary key) from several applications, and I’d like to avoid duplicating the join logic in various places to also retrieve their emails. So I think some kind of expression index would be best, if that’s possible.
If this isn’t possible, I suppose my next best option would be to create a view that the other applications could use to easily fetch a user’s emails along with their other information, but I’m not sure how to do that either.
I’m using Postgres 8.4. Thank you!
I think you’ll have to use a trigger to enforce your cross-column uniqueness constraint. If you add unique indexes on each column and then a trigger something like this (untested off the top of my head code):
You’d want something like that as a BEFORE INSERT and BEFORE UPDATE trigger. That trigger would take care of catching cross-column duplicates and the unique indexes would take care of in-column duplicates.
Some useful references:
FOUNDRAISETriggersYou’ll want the individual indexes for your queries anyway and using the uniqueness half of the indexes simplifies your trigger by leaving it to only deal with the cross-column part; if you try to do it all in the trigger, then you’ll have to watch out for updating a row without really changing the
emailoremail_newcolumns.For the querying half, you could create a view that used a
UNIONto combine the two columns. You could also create a function to merge the user’s email addresses into one list. Hard to say which would be best without know more details of these other queries but I suspect that fixing all the other queries to know aboutemailandemail_newwould be the best approach; you’ll have to update all the other queries to use the view or function anyway so why build a view or function at all?