I'm looking at the MySQL docs here and trying to sort out the distinction between FOREIGN KEYs and CONSTRAINTs. I thought an FK was a constraint, but the docs seem to talk about them like they're separate things.
The syntax for creating an FK is (in part)...
[CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (index_col_name, ...)
REFERENCES tbl_name (index_col_name,...)
So the "CONSTRAINT" clause is optional. Why would you include it or not include it? If you leave it out does MySQL create a foreign key but not a constraint? Or is it more like a "CONSTRAINT" is nothing more than a name for you FK, so if you don't specify it you get an anonymous FK?
Any clarification would be greatly appreciated.
Thanks,
Ethan
Yes, a foreign key is a type of constraint. MySQL has uneven support for constraints:
PRIMARY KEY: yes as table constraint and column constraint.
FOREIGN KEY: yes as table constraint, but only with InnoDB and BDB storage engines; otherwise parsed but ignored.
CHECK: parsed but ignored in all storage engines.
UNIQUE: yes as table constraint and column constraint.
NOT NULL: yes as column constraint.
DEFERRABLE and other constraint attributes: no support.
The CONSTRAINT clause allows you to name the constraint explicitly, either to make metadata more readable or else to use the name when you want to drop the constraint. The SQL standard requires that the CONSTRAINT clause is optional. If you leave it out, the RDBMS creates a name automatically, and the name is up to the implementation.
In general (not necessary MySQL), foreign keys are constraints, but constraints are not always foreign keys. Think of primary key constraints, unique constraints etc.
Coming back to the specific question, you are correct, omitting CONSTRAINT [symbol] part will create a FK with an auto-generated name.
As of now, our CREATE TABLE DDLs are of this format - notice the UNIQUE KEY and FOREIGN KEY definition syntax we have used.
CREATE TABLE my_dbschema.my_table (
id INT unsigned auto_increment PRIMARY KEY,
account_nbr INT NOT NULL,
account_name VARCHAR(50) NOT NULL,
active_flg CHAR(1) NOT NULL DEFAULT 'Y',
vendor_nbr INT NOT NULL,
create_ts TIMESTAMP NOT NULL DEFAULT current_timestamp,
create_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
last_upd_ts TIMESTAMP NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp,
last_upd_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
UNIQUE KEY uk1_my_table(account_nbr, account_name),
FOREIGN KEY fk1_my_table(vendor_nbr) REFERENCES vendor(vendor_nbr)
);
In this format, MySQL is creating INDEX-es with the names uk1_my_table and fk1_my_table automatically; but the FK object name is something different - my_table_ibfk_1 (ie. tablename_ibfk_N – system defined) . So ALTER TABLE my_table DROP FOREIGN KEY fk1_my_table won’t work (and hence frustrating and raising alarms), as there’s no FK db object by that name.
Here’s an alternative DDL format wrt the constarints (Ref : https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html) :-
CREATE TABLE my_dbschema.my_table (
id INT unsigned auto_increment PRIMARY KEY,
account_nbr INT NOT NULL,
account_name VARCHAR(50) NOT NULL,
active_flg CHAR(1) NOT NULL DEFAULT 'Y',
vendor_nbr INT NOT NULL,
create_ts TIMESTAMP NOT NULL DEFAULT current_timestamp,
create_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
last_upd_ts TIMESTAMP NOT NULL DEFAULT current_timestamp ON UPDATE current_timestamp,
last_upd_usr_id VARCHAR(10) NOT NULL DEFAULT 'DFLTUSR',
CONSTRAINT uk1_my_table UNIQUE KEY (account_nbr, account_name),
CONSTRAINT fk1_my_table FOREIGN KEY (vendor_nbr) REFERENCES vendor(vendor_nbr)
);
In this format, MySQL is still creating INDEX-es with the names uk1_my_table and fk1_my_table automatically, but the FK object name is not something different – it’s fk1_my_table as mentioned in the DDL. So ALTER TABLE my_table DROP FOREIGN KEY fk1_my_table works, but leaves behind the namesake INDEX.
And, note that ALTER TABLE my_table DROP INDEX fk1_my_table won’t work initially (when the FK is not yet dropped), with an error message that it is being used in a FK! If the DROP FK command has been executed successfully, only then the DROP INDEX works.
Hope this explains and helps resolve the confusion.
Can't answer for MySQL but FK's are constraints. Anything that forces your data into a certain condition is a constraint. There are several kinds of constraints, Unique, Primary Key, Check and Foreign Keys are all constraints. Maybe MySQL has others.
Sometimes words are allowed in commands but not required sheerly for readability like the FROM in the DELETE statement.
If I'm not wrong, the constraints need indexes, so when you create, for example, a foreign key constraint MySQL automatically creates an index too.
I am going to throw my hat in the ring here, although I don't actually know if my answer is accurate, so if you know the internal guts of database engineering, please correct me. But if I am right, I think this will help.
A Foreign Key and its associated Foreign Key Constraint are not the same thing, in the way a car engine and a crank-shaft are not the same thing. The engine converts gasoline explosions into straight line motion (the pistons), and the crankshaft converts that straight-line motion into turning motion, which then turns the wheels of the car. Together, the engine and the crank-shaft make the car go.
Likewise, a Foreign Key and a Foreign Key Constraint are not the same thing, but they work together to create the idea of a "Foreign Key Relationship".
DEFINITIONS:
"Foreign Key" is short for Foreign Key Index.
"Constraint" is short for Foreign Key Constraint.
The Index and the Constraint together make the "Foreign Key Relationship".
The Foreign Key Relationship is the requirement for a value in a child table to exist in its parent table, thus ensuring data integrity in a database.
Because Key means Index, we don't say "Foreign Key Index". We just say Foreign Key, but not saying "Index" is the cause of much confusion.
Creating a Foreign Key (a Foreign Key Index) creates a Binary Search Tree (also called a dictionary, because the tree is used to look up values). The Binary Search Tree (BST) then exists in computer memory and takes up physical disk space, but allows for O(log n) JOIN access time (almost instantly) from the child table to the parent table.
Creating a Foreign Key Constraint is creating a rule, which is a piece of code that gets called when you process (INSERT, SELECT, etc...) on the foreign key column. A constraint is essentially a database trigger. A constraint is like an email filter: a piece of code that gets called on a certain action, such as WHEN (new email) IF (From: crzy#xgfrnd.com) {SEND TO Trash Folder;}.
Thus, a Foreign Key "Constraint" would be a piece of code that gets called (a trigger, essentially), that looks like such: WHEN INSERT child_column IF (NOT IN parent_table) DO NOT ALLOW INSERT.
And then you have your Cascades and Updates and Delete rules (constraints), wth their various if / then conditions and operations, etc...
So, a "Foreign Key" is a BST dictionary mapping child table column values to parent table column values. The purpose of the Foreign Key is speed (NOT data integrity, since data integrity can be achieved, albeit slowly, without an index).
A Foreign Key Constraint is a rule: code that gets triggered on SQL statements, and that rule uses the BST as a dictionary for fast processing, to avoid traversing tables, which may eventually create Cartesian-like behavior. The purpose of the Foreign Key Constraint is data integrity.
I have never created a parent table where the referenced parent column was not itself a key in the parent table. So the question then is, is the Foreign Key Index (the BST dictionary) actually needed? The Constraint is definitely needed, to ensure data integrity, but Foreign Key Index (the BST dictionary) is actually not needed to fulfill the Foreign Key rule, thus, "Key" and "Index" have two different definitions. The "Index" is the BST tree, and the "Key" is the rule (the idea that the child value must exist in the parent table). In MySQL, however, the Foreign Key Index is needed, only because they programmed it that way, but they didn't have to. Having a BST tree is just faster, when the parent column is not itself indexed. I would never recommend making the referenced parent column not a key (index). But if someone did reference a non-indexed parent column using a Foreign Key Constraint without a BST, then the SQL operations would be progressively slow, and your application may eventually come to a crawl.
THE CONFUSION: Adjectives and verbs.
When we say "Foreign Key" colloquially, we are usually referring to the Foreign Key Relationship, not the Foreign Key Index. But the word Key means Index. So that's the root source of all the confusion. I.e. lack of reserved keyword definition standards. In a MySQL CREATE TABLE statement, FOREIGN KEY means the Index (the BST), and CONSTRAINT names the rule, therefore, the confusion is coming from the difference in the phrase "Foreign Key" when we speak, versus "Foreign Key" being defined in an actual SQL statement.
In computer code, "Foreign" is an adjective and "Key" is a noun, meaning the Index.
In colloquial speech, the phrase "Foreign Key" is an adjective, and the words "Index", "Constraint", and "relationship" are all nouns. When we speak to each other across office cubicles, "Foreign Key" means the "idea" of data integrity (i.e. the rule, not the index).
Unfortunately, programmers are always searching for short-hand ways of typing, which often causes confusion. Everything in computer science is a trade-off, and that includes coding style.
If the syntax for creating a MySQL table instead used the following reserved words, then the confusion would disappear: FOREIGN KEY CONSTRAINT fk1_rule_child_column FOREIGN KEY INDEX (fk_bst_child_to_parent_column) REFERENCES parent_table (parent_column)
Furthermore, since MySQL always creates both an Index and a Constraint, the MySQL creators could have completely hidden (abstraction) the dual element of the Foreign Key Relationship. Or, perhaps I should say, they could have bundled them together so the user doesn't have to think about the dual aspect, and instead just creates a "Foreign Key" my_foreign_key with the dual details hidden.
Nevertheless, MySQL is inexpensive, robust, and it's great. For the record, I have zero complaints, and I have only gratitude for the creators. For my part, they can do as they please.
Incidentally, as a style recommendation, you should ALWAYS name your parent and child columns the same, and your table names should ALWAYS contain their Foreign Key Relationships. So your tables
customers
products
attributes
orders
should instead be named
customers
products
product_attributes
customer_product_orders
That way, you and your successors know the foreign key relationships just by reading any table name. If that's too much typing for you, then
cust
prod
prod_attr
cust_prod_ord
That being said, I am guessing. I don't actually know if my BST and Rule explanation is correct, but I think it's correct, and hopefully will clear up this confusing issue. But I would appreciate if you database-guts guys out there would either confirm, modify, supplement, or deny what I have written, and if I am mistaken, what is the real answer, so we can finally get this multi-generational mystery solved. If I am completely off, and this answer needs to be deleted, that is fine too.
This is probably the most confusing topìc in MySQL.
Many people say that, for instance, the 'PRIMARY KEY', the 'FOREIGN KEY', and the 'UNIQUE' key are actually indexes! (MySQL official documentation is included here)
Many others, on the other hand, say that they're rather constraints (which does make sense, cause when you use them, you're really imposing restrictions on the affected columns).
If they really are indexes, then what's the point in using the constraint clausule in order to give it a name, since you're supposed to be able to use the name of that index when you created it?
Example:
... FOREIGN KEY index_name (col_name1, col_name2, ...)
If FOREIGN KEY is an index, then we should be able to use the index_name to handle it. However, we can't.
But if they're not indexes but actual contraints which do use indexes to work, then this does make sense.
In any case, we don't know. Actually, nobody seems to know.
Related
I am trying to understand the syntaxes for defining tables and I noticed that the column definitions include an option to indiciate that the column references a column from another table.
If I can already define this here, do I still need to explicitly define a FOREIGN KEY constraint specifying that column again? Why?
Because I imagine the REFERENCE definition added as a column constraint should already take care of the fact that the column is a foreign key (since it is referencing another table).
Example code for clarity:
a)
create table SAMPLE (
sample_id INT PRIMARY KEY,
client_id INT REFERENCES CLIENT (client_id)
);
b)
create table SAMPLE (
sample_id INT PRIMARY KEY,
client_id INT NOT NULL,
CONSTRAINT fk_sample_client
FOREIGN KEY (client_id) REFERENCES CLIENT (client_id)
);
Does definition (a) ensure that the clientId is identified as the foreign key, the same way definition (b) does?
REFERENCES as part of the column definition is ignored.
Important
For users familiar with the ANSI/ISO SQL Standard, please
note that no storage engine, including InnoDB, recognizes or enforces
the MATCH clause used in referential integrity constraint definitions.
Use of an explicit MATCH clause does not have the specified effect,
and also causes ON DELETE and ON UPDATE clauses to be ignored. For
these reasons, specifying MATCH should be avoided.
The MATCH clause in the SQL standard controls how NULL values in a
composite (multiple-column) foreign key are handled when comparing to
a primary key. InnoDB essentially implements the semantics defined by
MATCH SIMPLE, which permit a foreign key to be all or partially NULL.
In that case, the (child table) row containing such a foreign key is
permitted to be inserted, and does not match any row in the referenced
(parent) table. It is possible to implement other semantics using
triggers.
Additionally, MySQL requires that the referenced columns be indexed
for performance. However, InnoDB does not enforce any requirement that
the referenced columns be declared UNIQUE or NOT NULL. The handling of
foreign key references to nonunique keys or keys that contain NULL
values is not well defined for operations such as UPDATE or DELETE
CASCADE. You are advised to use foreign keys that reference only keys
that are both UNIQUE (or PRIMARY) and NOT NULL.
MySQL parses but ignores “inline REFERENCES specifications” (as
defined in the SQL standard) where the references are defined as part
of the column specification. MySQL accepts REFERENCES clauses only
when specified as part of a separate FOREIGN KEY specification. For
more information, see Section 1.7.2.3, “FOREIGN KEY Constraint
Differences”.
Source: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
As Simon shared , inline REFERENCES in column definitions are ignored by mySQL and this link gives further explanation as to why.
Defining a column to use a REFERENCES tbl_name(col_name) clause has no
actual effect and serves only as a memo or comment to you that the
column which you are currently defining is intended to refer to a
column in another table.
Simply put, the syntax will still only create the column; it will not specify it as a foreign key or carry out any checks on it.
I get a E-R model which is not designed by me. But I have no way to contact the author.
There are something confusing me in this model.
In Table A, the Primary Key is an integer field. Table B has a Foreign Key referenced to the PK of A. But this FK of B is a varchar field.
I just start learning the database dedign, and never see or do that in my jobs.
Is it reasonable and realizable?
Note that the model is for mysql.
That can't be implemented as a FOREIGN KEY constraint in InnoDB; the datatype of the foreign key column(s) must match the datatypes of the referenced column(s) EXACTLY.
You can perform a join operation on the columns, although there's going to need to be datatype conversion on one side or the other... e.g.
ON c.character_col + 0 = p.numeric_col
It's permissible to do that in SQL; we don't have to have a FOREIGN KEY constraint defined in order to perform join operations.
This design is not one we like to see; one of the big issues is performance, in that MySQL can't make effective use of an index on character_col.
I created my MySQL database using phpMyAdmin 3.5.8.1deb1 in Ubuntu.
Instead of that all my tables are InnoDB, I can't add a foreign key, and this is an example:
ALTER TABLE element ADD CONSTRAINT FK_element_id_user FOREIGN KEY (id_user) REFERENCES user(id) ON DELETE SET NULL ON UPDATE CASCADE;
When I run this script I get this error :
#1005 - Can't create table 'tpw.#sql-4d8_e2' (errno: 150) (Details...)
When I click on details I get this :
InnoDB Documentation Supports transactions, row-level locking, and foreign keys
I tried to add the FK manually in the relation view
There could be a couple of things going one here. Here are some things to look for:
Do the data types of each field between the tables match?
Are both both tables using the same MySQL engine?
Here is a good resource to help you debug this issue further.
Excerpt from the resource linked to above:
1) The two key fields type and/or size is not an exact match. For example, if one is INT(10) the key field needs to be INT(10) as well and not INT(11) or TINYINT. You may want to confirm the field size using SHOW CREATE TABLE because Query Browser will sometimes visually show just INTEGER for both INT(10) and INT(11). You should also check that one is not SIGNED and the other is UNSIGNED. They both need to be exactly the same.
2) One of the key field that you are trying to reference does not have an index and/or is not a primary key. If one of the fields in the relationship is not a primary key, you must create an index for that field.
3) The foreign key name is a duplicate of an already existing key. Check that the name of your foreign key is unique within your database. Just add a few random characters to the end of your key name to test for this.
4) One or both of your tables is a MyISAM table. In order to use foreign keys, the tables must both be InnoDB. (Actually, if both tables are MyISAM then you won’t get an error message – it just won’t create the key.) In Query Browser, you can specify the table type.
5) You have specified a cascade ON DELETE SET NULL, but the relevant key field is set to NOT NULL. You can fix this by either changing your cascade or setting the field to allow NULL values.
6) Make sure that the Charset and Collate options are the same both at the table level as well as individual field level for the key columns.
7) You have a default value (ie default=0) on your foreign key column.
8) One of the fields in the relationship is part of a combination (composite) key and does not have it’s own individual index. Even though the field has an index as part of the composite key, you must create a separate index for only that key field in order to use it in a constraint.
9) You have a syntax error in your ALTER statement or you have mistyped one of the field names in the relationship.
10) The name of your foreign key exceeds the max length of 64 chars.
User.ID has to be declared as an INDEX
Since primary key and unique is similar. I have trouble grasping the concept of the two. I know primary key doesnt accept null and unique key accepts a null once. Since a null value is a unique value so it can be only accepted once. But the idea of primary key is having a uniqueness in every row. which a unique key also do. thats why im asking when is it proper to use primary key over unique key and vice versa.
A UNIQUE constraint is similar to PRIMARY key, but you can have more than one UNIQUE constraint per table.
When you declare a UNIQUE constraint, SQL Server creates a UNIQUE index to speed up the process of searching for duplicates. In this case the index defaults to NONCLUSTERED index, because you can have only one CLUSTERED index per table.
The number of UNIQUE constraints per table is limited by the number of indexes on the table i.e 249 NONCLUSTERED index and one possible CLUSTERED index.
Contrary to PRIMARY key UNIQUE constraints can accept NULL but just once. If the constraint is defined in a combination of fields, then every field can accept NULL and can have some values on them, as long as the combination values is unique.
Also Refer other link (MSDN)
Executive summary: It is important for every base table to have a key, using either PRIMARY KEY or NOT NULL UNIQUE. The difference between the two is not a relational consideration and is not important from a logical point of view; rather, it is merely a psychological consideration.
a relvar can have several keys, but we choose just one for underlining
and call that one the primary key. The choice is arbitrary, so the
concept of primary is not really very important from a logical point
of view. The general concept of key, however, is very important! The
term candidate key means exactly the same as key (i.e., the addition
of candidate has no real significance—it was proposed by Ted Codd
because he regarded each key as a candidate for being nominated as the
primary key)... SQL allows a subset of a table's columns to be
declared as a key for that table. It also allows one of them to be
nominated as the primary key. Specifying a key to be primary makes
for a certain amount of convenience in connection with other
constraints that might be needed
What Is a Key? by Hugh Darwen
it's usual... to single out one key as the primary key (and any other
keys for the relvar in question are then said to be alternate keys).
But whether some key is to be chosen as primary, and if so which one,
are essentially psychological issues, beyond the purview of the
relational model as such. As a matter of good practice, most base
relvars probably should have a primary key—but, to repeat, this rule,
if it is a rule, really isn't a relational issue as such... Strong
recommendation [to SQL users]: For base tables, at any rate, use
PRIMARY KEY and/or UNIQUE specifications to ensure that every such
table does have at least one key.
SQL and Relational Theory: How to Write Accurate SQL Code
By C. J. Date
In standard SQL PRIMARY KEY
implies uniqueness but you can specify that explicitly (using UNIQUE).
implies NOT NULL but you can specify that explicitly when creating columns (but you should be avoiding nulls anyhow!)
allows you to omit its columns in a FOREIGN KEY but you can specify them explicitly.
can be declared for only one key per table but it is not clear why (Codd, who originally proposed the concept, did not impose such a restriction).
In some products PRIMARY KEY implies the table's clustered index but you can specify that explicitly (you may not want the primary key to be the clustered index!)
For some people PRIMARY KEY has purely psychological significance:
they think it signifies that the key will be referenced in a foreign key (this was proposed by Codd but not actually adopted by standard SQL nor SQL vendors).
they think it signifies the sole key of the table (but the failure to enforce other candidate keys leads to loss of data integrity).
they think it implies a 'surrogate' or 'artificial ' key with no significance to the business (but actually imposes unwanted significance on the enterprise by being exposed to users).
A table can have multiple UNIQUE key but only one PRIMARY key is allowed for a table.
IF your unique key is a NOT NUL UNIQUE KEY then it is always a good idea to promote it to PRIMARY KEY.
If your storage engine is INNODB and if you don't have any PRIMARY key then innodb automatically creates a internal HEXDECIMAL PRIMARY key which will have some performance impact, hence it is better to create a primary key always with INNODB storage engine.
A PK is considered to be an unique identifier of the row. It should never be subject to changes. For example the ID of the User.
An UK is considered to be unique throughout the whole column. It is not necessarily an identifier of the row as it may be subject to changes. For example the username or email address of the User.
So I'm attempting to add a new foreign key to one of my tables as such:
ALTER TABLE `UserTransactions`.`ExpenseBackTransactions`
ADD CONSTRAINT `FK_EBTx_CustomAccountID`
FOREIGN KEY (`CustomAccountID` )
REFERENCES `UserTransactions`.`CustomAccounts` (`CustomAccountID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
ADD INDEX `FK_EBTx_CustomAccountID` (`CustomAccountID` ASC) ;
and I keep getting the following error:
Error Code: 1005
Can't create table './UserTransactions/#sql-187a_29.frm' (errno: 150)
I've done quite a bit of changes in the past to this and other tables, and this is the first time I've run into this issue. Any ideas what is causing it?
UPDATE
My SHOW INNODB STATUS error:
------------------------
LATEST FOREIGN KEY ERROR
------------------------
110525 15:56:36 Error in foreign key constraint of table UserTransactions/#sql-187a_2c:
FOREIGN KEY (`CustomAccountID` )
REFERENCES `UserTransactions`.`CustomAccounts` (`CustomAccountID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION
, ADD INDEX `FK_EBTx_CustomAccountID` (`CustomAccountID` ASC):
Cannot resolve table name close to:
(`CustomAccountID` )
ON DELETE NO ACTION
ON UPDATE NO ACTION
, ADD INDEX `FK_EBTx_CustomAccountID` (`CustomAccountID` ASC)
There's a nice checklist here.
Below is a running list of known causes that people have reported for the dreaded errno 150:
The two key fields type and/or size is not an exact match. For example, if one is INT(10) the key field needs to be INT(10) as well and not INT(11) or TINYINT. You may want to confirm the field size using SHOW CREATE TABLE because Query Browser will sometimes visually show just INTEGER for both INT(10) and INT(11). You should also check that one is not SIGNED and the other is UNSIGNED. They both need to be exactly the same. (More about signed vs unsigned here).
One of the key field that you are trying to reference does not have an index and/or is not a primary key. If one of the fields in the relationship is not a primary key, you must create an index for that field. (thanks to Venkatesh and Erichero and Terminally Incoherent for this tip)
The foreign key name is a duplicate of an already existing key. Check that the name of your foreign key is unique within your database. Just add a few random characters to the end of your key name to test for this. (Thanks to Niels for this tip)
One or both of your tables is a MyISAM table. In order to use foreign keys, the tables must both be InnoDB. (Actually, if both tables are MyISAM then you won’t get an error message – it just won’t create the key.) In Query Browser, you can specify the table type.
You have specified a cascade ON DELETE SET NULL, but the relevant key field is set to NOT NULL. You can fix this by either changing your cascade or setting the field to allow NULL values. (Thanks to Sammy and J Jammin)
Make sure that the Charset and Collate options are the same both at the table level as well as individual field level for the key columns. (Thanks to FRR for this tip)
You have a default value (ie default=0) on your foreign key column (Thanks to Omar for the tip)
One of the fields in the relationship is part of a combination (composite) key and does not have its own individual index. Even though the field has an index as part of the composite key, you must create a separate index for only that key field in order to use it in a constraint. (Thanks to Alex for this tip)
You have a syntax error in your ALTER statement or you have mistyped one of the field names in the relationship (Thanks to Christian & Mateo for the tip)
The name of your foreign key exceeds the max length of 64 chars. (Thanks to Nyleta for the tip)
In my experience, the errno: 150 usually indicates that the data types of the FOREIGN KEY column in the key table and relating table are not identical. Make sure that CustomAccounts.CustomAccountID and ExpenseBackTransactions.CustomAccountIDare the exact same type, including UNSIGNED if it applies.
If that doesn't help, please post the SHOW CREATE TABLE ExpenseBackTransactions; and SHOW CREATE TABLE CustomAccounts;
Catch 22. Foreign keys need indexes. MySQL doesn't order this query so that the index exists at the time it does it foreign key checks. Thus, first create the index, then add the foreign key in 2 separate queries.