Clarification - Default Foreign Key Constraints - InnoDB - mysql

MySQL Server version: 5.6.17
I have two tables:
vatbands:
`vatbands_id` INT(11) UNSIGNED NOT NULL,
`client_id` INT(11) UNSIGNED NOT NULL COMMENT 'Customer ID',
`code` ENUM('A', 'B', 'C', 'D', 'E', 'F') NOT NULL,
PRIMARY KEY (`vatbands_id`, `code`, `client_id`),
INDEX `vatcode_vatbands` (`code` ASC, `client_id` ASC)
ENGINE = InnoDB;
1 row in vatbands:
INSERT INTO `vatbands` (`client_id`, `code`) VALUES ('1', 'A');
items:
`client_id` INT(11) UNSIGNED NOT NULL,
`vatcode` ENUM('A', 'B', 'C', 'D', 'E', 'F') NOT NULL DEFAULT 'A',
PRIMARY KEY (`item_id`, `client_id`),
INDEX `vatcode_item` (`vatcode` ASC, `client_id` ASC),
CONSTRAINT `vatcode_item`
FOREIGN KEY (`vatcode` , `client_id`)
ENGINE = InnoDB;
Inserting into child (item) table:
INSERT INTO `item` (`client_id`, `code`) VALUES ('1', '');
When I try to insert into my items table without specifying a vatcode i get foreign key constraint failure:
Cannot add or update a child row: a foreign key constraint fails (`mydb`.`item`, CONSTRAINT `vatcode_item` FOREIGN KEY (`vatcode`, `client_id`) REFERENCES `vatbands` (`code`, `client_id`) ON DELETE NO ACTION ON UPDATE NO ACTION)
Why is this, I thought specifying a default value for the vatcode would allow this to continue (as long as the row exists)?
I have checked the InnoDB manual:
14.6.6 InnoDB and FOREIGN KEY Constraints
Referential actions for foreign keys of InnoDB tables are subject to
the following conditions:
While SET DEFAULT is allowed by the MySQL Server, it is rejected as
invalid by InnoDB.
Is this the reason it is failing?
UPDATE:
If i input a value directly using PHP:
INSERT INTO `item` (`client_id`, `code`) VALUES ('1', 'A');
The constraint succeeds as expected.

The SET DEFAULT clause for a foreign key has nothing to do with inserting to the child table. It declares what to do with dependent rows in the child table if the referenced row in the parent table is deleted or updated.
Example: If an employee belongs to a department, and the department is deleted, should the employee be fired as well? Or should they be reassigned to some other "default" department?
I tested your example, and I find that it works fine, but you must specify at least a client_id that exists in the parent table.
mysql> insert into items (client_id) values (1);
Query OK, 1 row affected (0.00 sec)
I also notice that your key in vatbands on (code,client_id) is a non-unique key. It should really be a primary key or unique key to be referenced by a foreign key of a child table. In fact, when I test with MySQL 5.7 milestone release, I can't even create the items table because apparently in this regard the new version of MySQL is more strict than older versions. So I had to make your key a primary key. Then the test worked.

The only way I could get this to work is inserting a default using PHP.
INSERT INTO `item` (`client_id`, `code`) VALUES ('1', 'A');
If anyone has any better ways of resolving this please don't hesitate to comment, I would much prefer a pure MySQL method.

If you use:
INSERT INTO `item` (`client_id`, `code`) VALUES ('1', '');
You are not inserting NULL but an empty string.
INSERT INTO `item` (`client_id`, `code`) VALUES ('1', NULL);
will work

Related

MySQL INSERT not working as expected

This query is running an upsert which is being called from PHP, I wasn't getting the updates except for one table, which was really odd. I tried the query and noticed this was seeming to be the case. If I run it for the following value, the row does not update.
Row
operation_attendee_id operation_id member_id status
1 5 1 1
Query:
INSERT INTO
`operation_attendee` (
`operation_id`,
`member_id`,
`status`)
VALUES
(5,
1,
3)
ON DUPLICATE KEY UPDATE
`status` = 3
This will not update the table, but there is a unique index on operation_id, member_id
If I run for this row
operation_attendee_id operation_id member_id status
0 7 1 1
Same exact query, different numbers
INSERT INTO
`operation_attendee` (
`operation_id`,
`member_id`,
`status`)
VALUES
(7,
1,
3)
ON DUPLICATE KEY UPDATE
`status` = 3
This one updates fine. I'm really perplexed as to why this seems to be the only value set that is updating.
EDIT: Adding table DDL and all indexes:
CREATE TABLE `operation_attendee` (
`operation_attendee_id` int(11) NOT NULL,
`operation_id` int(11) NOT NULL,
`member_id` int(11) NOT NULL,
`status` int(11) NOT NULL,
PRIMARY KEY (`operation_attendee_id`),
UNIQUE KEY `uk_operation_member` (`operation_id`,`member_id`),
KEY `fk_operation_attendee_operation1_idx` (`operation_id`),
KEY `fk_operation_attendee_member1_idx` (`member_id`),
KEY `fk_operation_attendee_operation_attendee_status1_idx` (`status`),
CONSTRAINT `fk_operation_attendee_member1` FOREIGN KEY (`member_id`) REFERENCES `member` (`member_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_operation_attendee_operation1` FOREIGN KEY (`operation_id`) REFERENCES `operation` (`operation_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_operation_attendee_operation_attendee_status1` FOREIGN KEY (`status`) REFERENCES `operation_attendee_status` (`operation_attendee_status_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8
I also tried to run the query with foreign key check off and it still doesn't update.
and
It seems it was an issue with the surrogate key.
I removed it (it was not needed for that table, someone else built it a long while back), and then replace the primary key with the unique key I was using prior (removed the unique key as well since it was redundant) the query now seems to be working fine.
I'm not sure why it was causing issues in terms of an underlying reason, but it works now. I would think the unique key I put on the table would have matched the conditions for the ON DUPLICATE KEY UPDATE requirement.

FOREIGN KEY references same table's column. Can't insert values

I created table with FOREIGN KEY and can't insert anything.
CREATE TABLE menus (
id int(10),
parent_id int(10),
label varchar(255),
PRIMARY KEY (id),
FOREIGN KEY (parent_id) REFERENCES menus (id)
);
I need FOREIGN KEY to automatically delete children when parent was deleted. This table was successfully created but I can't insert anything.
INSERT INTO `menus` (`parent_id`, `label`)
VALUES ('1', 'label1');
or
INSERT INTO `menus` (`label`)
VALUES ( 'label1');
#1452 - Cannot add or update a child row: a foreign key constraint fails
I really don't want look for any children in php code so I need somehow create simple table with 3 columns and automatically drop all children and they children too.
For all your needs you should take this structure
CREATE TABLE `menus` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(11) unsigned DEFAULT NULL,
`label` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `fk_parent_menu` (`parent_id`),
CONSTRAINT `fk_parent_menu` FOREIGN KEY (`parent_id`)
REFERENCES `menus` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
);
SQL Fiddle DEMO
Demo shows inserting and deleting of a parent node
The magic drop part for all children is done by ON DELETE CASCADE
Typically, you will need to allow the 'root' record to have a null parent - i.e. menus.parent_id should be nullable, and the 'root' menu item will have a null parent_id.
i.e.
Change your DDL to:
parent_id int(10) NULL
And then you add your root element with NULL as the parent_id
insert into `menus` (id, `label`, parent_id)
VALUES (1, 'label1', null);
Then you are good to go with child elements:
insert into `menus` (id, `label`, parent_id)
VALUES (2, 'subitem1', 1);
etc.
SQL Fiddle here

MySQL: error on truncate `myTable` when FK has on Delete Cascade enabled

i have a problem with a mysql ERM which is currently driving me crazy. I have a table called usuaris_backoffice used to store backoffice users, then i also have a table called usuaris_backoffice_permisos used to store the privileges of every user. I also have a table called perfils where i store some profiles which can be edited by the backoffice users so to have a edition history there is a tabled called perfils_usuari_backoffice where i store which profile has been modified by each user. Then i also have a tabled called widgets which also can be edited by the users, so the widgets edition history is stored in widgets_usuari_backoffice. The FK are enabled for cascade deletion, so when a user is deleted from usuaris_backoffice its privileges are also deleted from usuaris_backoffice_permisos. The problem appears when i try to:
truncate usuaris_backoffice_permisos
which gives me the following error:
1701 - Cannot truncate a table referenced in a foreign key constraint (`test`.`usuaris_backoffice_permisos`, CONSTRAINT `FK_F8F850F3D001730C` FOREIGN KEY (`usuari_backoffice_id`) REFERENCES `test`.`usuaris_backoffice` (`id`))
As this 6 tables are part of a biggest ERM i've created a small test environment in order to be able to run some tests, so the following code can be used to create and populate the tables:
CREATE TABLE perfils_usuari_backoffice (perfil_id INT NOT NULL, login VARCHAR(20) NOT NULL, updated_at DATETIME NOT NULL, INDEX IDX_870785D657291544 (perfil_id), INDEX IDX_870785D6AA08CB10 (login), PRIMARY KEY(perfil_id, login, updated_at)) ENGINE = InnoDB;
CREATE TABLE usuaris_backoffice (id INT AUTO_INCREMENT NOT NULL, login VARCHAR(20) NOT NULL, password VARCHAR(32) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, UNIQUE INDEX UNIQ_95E4B6E5AA08CB10 (login), PRIMARY KEY(id)) ENGINE = InnoDB;
CREATE TABLE usuaris_backoffice_permisos (id INT AUTO_INCREMENT NOT NULL, usuari_backoffice_id INT NOT NULL, es_admin TINYINT(1) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, INDEX IDX_F8F850F3D001730C (usuari_backoffice_id), PRIMARY KEY(id)) ENGINE = InnoDB;
CREATE TABLE widgets_usuari_backoffice (widget_id INT NOT NULL, usuari_backoffice_id INT NOT NULL, updated_at DATETIME NOT NULL, INDEX IDX_43DA3B33FBE885E2 (widget_id), INDEX IDX_43DA3B33D001730C (usuari_backoffice_id), PRIMARY KEY(widget_id, usuari_backoffice_id, updated_at)) ENGINE = InnoDB;
CREATE TABLE widgets (id INT AUTO_INCREMENT NOT NULL, classe VARCHAR(20) NOT NULL, updated_at DATETIME NOT NULL, UNIQUE INDEX UNIQ_9D58E4C18F87BF96 (classe), PRIMARY KEY(id)) ENGINE = InnoDB;
CREATE TABLE perfils (id INT AUTO_INCREMENT NOT NULL, actiu TINYINT(1) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY(id)) ENGINE = InnoDB;
ALTER TABLE perfils_usuari_backoffice ADD CONSTRAINT FK_870785D657291544 FOREIGN KEY (perfil_id) REFERENCES perfils (id) ON DELETE CASCADE;
ALTER TABLE usuaris_backoffice_permisos ADD CONSTRAINT FK_F8F850F3D001730C FOREIGN KEY (usuari_backoffice_id) REFERENCES usuaris_backoffice (id) ON DELETE CASCADE;
ALTER TABLE perfils_usuari_backoffice ADD CONSTRAINT FK_870785D6AA08CB10 FOREIGN KEY (login) REFERENCES usuaris_backoffice (login) ON DELETE CASCADE;
ALTER TABLE widgets_usuari_backoffice ADD CONSTRAINT FK_43DA3B33D001730C FOREIGN KEY (usuari_backoffice_id) REFERENCES usuaris_backoffice (id) ON DELETE CASCADE;
ALTER TABLE widgets_usuari_backoffice ADD CONSTRAINT FK_43DA3B33FBE885E2 FOREIGN KEY (widget_id) REFERENCES widgets (id) ON DELETE CASCADE;
INSERT INTO `test`.`usuaris_backoffice` (`id` ,`login` ,`password` ,`created_at` ,`updated_at`)VALUES (NULL , 'edgar', '1234', '2011-10-06 00:00:00', '2011-10-06 00:00:00');
INSERT INTO `test`.`usuaris_backoffice_permisos` (`id`, `usuari_backoffice_id`, `es_admin`, `created_at`, `updated_at`) VALUES (NULL, '1', '0', '2011-10-06 00:00:00', '2011-10-06 00:00:00');
INSERT INTO `test`.`perfils` (`id`, `actiu`, `created_at`, `updated_at`) VALUES (NULL, '0', '2011-10-06 00:00:00', '2011-10-06 00:00:00');
INSERT INTO `test`.`perfils_usuari_backoffice` (`perfil_id`, `login`, `updated_at`) VALUES ('1', 'edgar', '2011-10-06 00:00:00');
INSERT INTO `test`.`widgets` (`id`, `classe`, `updated_at`) VALUES (NULL, 'hola', '2011-10-06 00:00:00');
INSERT INTO `test`.`widgets_usuari_backoffice` (`widget_id`, `usuari_backoffice_id`, `updated_at`) VALUES ('1', '1', '2011-10-06 00:00:00');
Code which returns the error is:
TRUNCATE usuaris_backoffice_permisos;
TRUNCATE perfils_usuari_backoffice;
TRUNCATE widgets_usuari_backoffice;
TRUNCATE usuaris_backoffice;
Thanks a lot for your time, hope someone can help :)
Take a look http://dev.mysql.com/doc/refman/5.5/en/truncate-table.html. It says
TRUNCATE TABLE fails for an InnoDB table if there are any FOREIGN KEY constraints from other tables that reference the table. Foreign key constraints between columns of the same table are allowed.
From here it looks it worked in some previous versions
SET FOREIGN_KEY_CHECKS = 0;
Then truncate your tables.

Composite foreign key constraint

The composite foreign key indexes do not work as I thought it would.
In the following example, I want only the 10 combinations to be allowed in the child table. But the last insert statement is successful even if there is no matching combination in the parent table.
Is there any other way to achieve that kind of constraint?
drop table if exists child;
drop table if exists parent;
CREATE TABLE parent(
`ID` int(11) default NULL,
`name` varchar(100) default NULL,
`city` varchar(100) default NULL,
key (name,city),
key (ID)
) ENGINE=InnoDB;
create table child(
userID int not null,
`name` varchar(100) default NULL,
`city` varchar(100) default NULL,
key (name,city),
FOREIGN KEY (name,city) REFERENCES parent(name,city),
primary key (userID)
) ENGINE=InnoDB;
insert into parent values (1, 'Amar', 'mumbai');
insert into parent values (2, 'Amar', 'Delhi');
insert into parent values (3, 'Amar', NULL);
insert into parent values (4, 'Akbar', 'mumbai');
insert into parent values (5, 'Akbar', 'Delhi');
insert into parent values (6, 'Akbar', NULL);
insert into parent values (7, 'Anthony', 'mumbai');
insert into parent values (8, 'Anthony', 'Delhi');
insert into parent values (9, 'Anthony', NULL);
insert into parent values (10, NULL, NULL);
insert into child values (2, NULL, 'mumbai');
Don't use nulls in foreign key columns; that way leads to the dark side. You should declare such columns NOT NULL.
According to the documentation
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.
since child.name field declared nullable it can contain null values. it does not violate foreign key concept.
the solution is to decalre fk fields as NOT NULL

mysql - what does this error mean?

I do not require this error to be solved. I just need to understand what it means so I can approach it myself.
Cannot add or update a child row: a foreign key constraint fails
(`db`.`transaction`, CONSTRAINT `transaction_ibfk_2`
FOREIGN KEY (`product_id`) REFERENCES `product` (`id`))
INSERT INTO `transaction` ( `client_id`, `cost`, `website_id`, `product_id`,
`template_number`, `value`, `order_id` )
VALUES ( '17', '', '2480', '', '', '12', '1');
What is a foreign key? How is it set?
What does CONSTRAINT transaction_ibfk_2 mean?
Does this mean I need to have a table called transaction_ibfk_2?
Thanks.
You are inserting an empty string as productid (Fourth item in the list)
INSERT INTO transaction
(client_id, cost, website_id, product_id, template_number, value, order_id)
VALUES ('17', '', '2480', '', '', '12', '1')
There is a referential integrity constraint set up to ensure that you must only insert productids matching one in the referenced product table.
This means you are trying to add a value into the foreign key column which is not available in the referenced column or trying to add blank in foreign key column.
i.e. You are trying to add product_id as blank which is not allowed. All values in foreign key column must be valid values present in the main referenced column id.
There's not necessarily a relationship between constraint names and tables although most people name them appropriately to make their lives easier.
All this means is that you have a transaction_ibfk_2 constraint. The actual problem is in the rest of the message:
FOREIGN KEY (product_id) REFERENCES product (id)
You need to insert a row into your product table first. The id that you insert there should be the product_id you're trying to insert into transaction (which is '' for some reason - I'm pretty certain this should be a real value (or possibly NULL)).
You can create foreign keys with a clause of the create table or alter table DDL statements.