Having first read all the documentation on Foreign Keys and hence side-stepping the most common pit-falls by making sure all my tables were of type InnoDB, all the columns involved had indices and had exactly matching types I was most disappointed to get a bizarre and senseless error from MySQL:
Can't create table './epath/#sql-1a1_f9.frm' (errno: 150)
I’m using the latest stable release of MySQL (5.0.22) on OS X 10.4 Tiger.
The first thing I tried to solve this was a bit of googling which led me to loads of threads reminding people about the obvious stuff I was sure to avoid (table type, indices & matching data types). However, deep in the bowls of one of these discussions I did discover that, despite the documentation’s utter failure to mention this fact, foreign keys apparently only work when the columns involved are un-signed numbers.
The columns I was trying to link first were both of type varchar so I tried with a different pair of columns of type int (which I first set as being un-signed). This worked so I took the identical syntax and tried again with my varchar‘s, no joy, just the same uninformative error. It then occurred to me that the items in these columns will always be exactly two characters long so I changed their type to char(2) but again I got the same nonsensical error.
Some more googling seems to confirm my theory that MySQL will only be happy with foreign keys that are numeric un-signed types. This is a serious problem for the project I’m now working on. My data has a load of primary keys that are non-numeric that need to referenced as foreign keys all over the place. The two most obvious examples being 2 letter department codes and 3 letter alpha-numeric machine IDs. I could hack this by creating additional integer auto-increment fields in my departments and hosts tables and using these as primary keys instead of the logical fields but that is wasteful and pointlessly complex.
This is my first foray back in to serious MySQL development for a year having used PostgreSQL in the interim and I think I’ll be switching back to PostgreSQL before you can say ‘MySQL sucks’.