MySQL Workbench generates combined primary key with unnecessary unique constraints - mysql

I have a problem during SQL generation of my database diagram from MySQL Workbench (UNIQUE constraints are added in every field from combined primary key).
I have following diagram: https://dl.dropboxusercontent.com/u/3843729/baza.png
Moreover, it has following properties set: https://dl.dropboxusercontent.com/u/3843729/indexes.png
SQL generated:
CREATE TABLE IF NOT EXISTS `test`.`User_has_Menu` (
`User_id` BIGINT UNIQUE NOT NULL,
`Menu_id` BIGINT UNIQUE NOT NULL,
PRIMARY KEY (`User_id`, `Menu_id`),
INDEX `fk_User_has_Menu_Menu1_idx` (`Menu_id` ASC),
INDEX `fk_User_has_Menu_User1_idx` (`User_id` ASC),
CONSTRAINT `fk_User_has_Menu_User1`
FOREIGN KEY (`User_id`)
REFERENCES `test`.`User` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_User_has_Menu_Menu1`
FOREIGN KEY (`Menu_id`)
REFERENCES `test`.`Menu` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
As you can see, 'User_id' and 'Menu_id' have UNIQUE keyword, so as a result I cannot insert single user_id (or menu_id) in two rows, for example:
insert into user_has_menu (user_id, menu_id) values (1,1);
insert into user_has_menu (user_id, menu_id) values (1,3);
Second insert statement is not executed as user_id must be unique.
Note: If I create new diagram in MySQL Workbench, everything is working fine and the SQL generated is without problematic UNIQUE constraints.
How can I remove those constraints without creating new diagram?

first find the unique constraint names:
select *
from
information_schema.key_column_usage
where
and table_schema = 'my_database'
and table_name = 'my_table'
then drop them
alter table my_table drop index my_contraint
And because unique constraints are handled as indexes on MySQL you can try make sure you don't have these indexes on the MySQL graphical interface.

Related

MySQL Workbench reports ERROR 1822: Failed to add the foreign key constraint. Missing index for constraint

I'm creating a mysql db based from an EER model sql script and when trying to do the conversion (all in MySQL Workbench), I'm getting the error above. My goal is to reference the adoption_entity_id on the adoption_entity table from 2 columns in attachment table (sent_from and from_to).
I have 2 tables, one of which is the attachment:
-- -----------------------------------------------------
-- Table `afth_db`.`attachment`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `afth_db`.`attachment` ;
CREATE TABLE IF NOT EXISTS `afth_db`.`attachment` (
`attachment_id` BIGINT NOT NULL,
`sent_from` INT NULL,
`sent_to` INT NULL,
`attachment_description` LONGTEXT NULL,
`attachment_uploaded` DATETIME NULL,
`attachment_uploaded_by` VARCHAR(255) NULL,
`adoption_case_num` BIGINT NOT NULL,
PRIMARY KEY (`attachment_id`),
INDEX `fk_attachment_adoption_case1_idx` (`adoption_case_num` ASC) VISIBLE,
UNIQUE INDEX `attachment_id_UNIQUE` (`attachment_id` ASC) VISIBLE,
UNIQUE INDEX `adoption_case_num_UNIQUE` (`adoption_case_num` ASC) VISIBLE,
INDEX `fk_attachment_adoption_entity1_idx` (`sent_from` ASC, `sent_to` ASC) VISIBLE,
UNIQUE INDEX `sent_to_UNIQUE` (`sent_to` ASC) VISIBLE,
UNIQUE INDEX `sent_from_UNIQUE` (`sent_from` ASC) VISIBLE,
CONSTRAINT `fk_attachment_adoption_case1`
FOREIGN KEY (`adoption_case_num`)
REFERENCES `afth_db`.`adoption_case` (`case_num`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_attachment_adoption_entity1`
FOREIGN KEY (`sent_from` , `sent_to`)
REFERENCES `afth_db`.`adoption_entity` (`adoption_entity_id` , `adoption_entity_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
and the other is the adoption entity:
-- -----------------------------------------------------
-- Table `afth_db`.`adoption_entity`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `afth_db`.`adoption_entity` (
`adoption_entity_id` INT NOT NULL,
`adoption_entity_type` VARCHAR(255) NULL,
PRIMARY KEY (`adoption_entity_id`),
UNIQUE INDEX `adoption_entity_id_UNIQUE` (`adoption_entity_id` ASC) VISIBLE)
ENGINE = InnoDB
The error states in detail:
Operation failed: There was an error while applying the SQL script to the database.
ERROR 1822: Failed to add the foreign key constraint. Missing index for constraint 'fk_attachment_adoption_entity1' in the referenced table 'adoption_entity'
I'm not sure why its been giving me this issue though. I've tried several solutions from setting type to 'unique index', 'index' for fk_attachment_adoption_entity1 along with the other columns involved, but I can't seem to be able to get rid of the error. I've also tried deleting and recreating the 1-1 relationship but that didnt help either. Can anyone tell me if I'm doing something wrong here on the EER model design?
You are trying to create one foreign key reference, which spans over the two columns sent_from and sent_to to single rows in the adoption_entity table. That's not what you want. You want to create two separate foreign key references instead for the individual columns sent_from and sent_to. So the constraint parts should look like this:
CONSTRAINT `fk_attachment_adoption_entity_from`
FOREIGN KEY (`sent_from`)
REFERENCES `afth_db`.`adoption_entity` (`adoption_entity_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION),
CONSTRAINT `fk_attachment_adoption_entity_to`
FOREIGN KEY (`sent_to`)
REFERENCES `afth_db`.`adoption_entity` (`adoption_entity_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)

MySQL mapping table insert constraint not working

I have a mapping table for customer and products. Here are the steps
create table `customer_products` (
`customer_id` bigint not null,
`product_id` bigint not null,
primary key (`customer_id`, `product_id`)
);
alter table `customer_products`
add constraint `FK7urin54lem7yxy6umxf899t16`
foreign key (`customer_id`)
references `customer` (`customer_id`);
alter table `customer_products`
add constraint `FKtfgjfwfykaef4wjk00ofyqq8y`
foreign key (`product_id`)
references `product` (`product_id`);
insert into customer_products values(7,5); //should get a contraint error
When I insert into this mapping table although the corresponsing entries are not there in the parent tables I am not getting an error in above insert statement . Do I need some extra option to put this constraint?
This approch is not good.
But have a solution.
You can write a trigger on customer_products and set 'before insert'
You need to write more intaligent query to insert in parent tables that records not exist.
I got it. The JPA was using MyISAM engine to create tables and it doesn't support foreign key constraints. So once I modified the engine to InnoDB the problem got resolved.

How to alter existing foreign key to add a constraint name

I had previously written my create queries as follows, where the foreign keys were unnamed.
CREATE TABLE My_Table_Name (
USER_ID VARCHAR(255) NOT NULL,
CONSENT_ID VARCHAR(255) NOT NULL,
PRIMARY KEY (USER_ID, CONSENT_ID),
FOREIGN KEY (CONSENT_ID) REFERENCES ANOTHER_TABLE_NAME (CONSENT_ID) ON DELETE CASCADE
);
Now the table has data in it and I want to add the constraint name to the existing foreign keys. How can I do that?
PS: What I need is an ALTER query
Also, if the database were SQL Server instead of MySQL, would the query be different?
Foreign key constraints in MySQL cannot be renamed once created. You will have to drop the constraint, then recreate it with the name you want.
First you are going to have to go digging for the foreign key constraint name (there is one, you just don't know what it is):
SELECT constraint_name
FROM information_schema.REFERENTIAL_CONSTRAINTS
WHERE constraint_schema = 'your_db_name' AND table_name = 'My_Table_Name';
Now rename the constraint:
ALTER TABLE My_Table_Name
DROP FOREIGN KEY some_foreign_key -- from above query
ADD CONSTRAINT fk_my_constraint FOREIGN KEY (CONSENT_ID)
REFERENCES ANOTHER_TABLE_NAME (CONSENT_ID) ON DELETE CASCADE;
You use the constraint keyword:
CREATE TABLE My_Table_Name (
USER_ID VARCHAR(255) NOT NULL,
CONSENT_ID VARCHAR(255) NOT NULL,
CONSTRAINT pk_mY_table_name PRIMARY KEY (USER_ID, CONSENT_ID),
CONSTRAINT fk_my_table_name_consent_id FOREIGN KEY (CONSENT_ID) REFERENCES ANOTHER_TABLE_NAME (CONSENT_ID) ON DELETE CASCADE
);
This is standard syntax and will be the same in almost any database.
In both databases, you will need to go through the metadata tables to get the name of the existing constraint. Then add a new one:
alter table my_table_name
drop constraint x,
drop constraint y;
alter table my_table_name
CONSTRAINT pk_mY_table_name PRIMARY KEY (USER_ID, CONSENT_ID),
CONSTRAINT fk_my_table_name_consent_id FOREIGN KEY (CONSENT_ID) REFERENCES ANOTHER_TABLE_NAME (CONSENT_ID) ON DELETE CASCADE;
You can get the constraint names from INFORMATION_SCHEMA.TABLE_CONSTRAINTS (see here). This is available in both databases. I do caution that the columns are sometimes different in the INFORMATION_SCHEMA tables.
In MS SQL, anonymous constraints will get a system generated name.
You could use the following query to fetch the generated constraint name:
SELECT
FK.CONSTRAINT_NAME
FROM
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON
PK.CONSTRAINT_CATALOG = RC.UNIQUE_CONSTRAINT_CATALOG AND
PK.CONSTRAINT_SCHEMA = RC.UNIQUE_CONSTRAINT_SCHEMA AND
PK.CONSTRAINT_NAME = RC.UNIQUE_CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON
FK.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG AND
FK.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA AND
FK.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
WHERE
FK.TABLE_NAME = N'My_Table_Name' AND
PK.TABLE_NAME = N'ANOTHER_TABLE_NAME'
This gives a result like 'FK__My_Table___CONSE__5535A963'.
Next, you might use the sp_rename stored procedure, like this:
EXECUTE sp_rename N'FK__My_Table___CONSE__5535A963', N'FK_MyRenamedConstraint';
Of course, you need to use the correct constraint names in your query.
(You may ignore the default warning from SQL Server about the fact that renaming might break existing scripts and stored procedures.)
When the first query is executed again, it will show you the new name.
I do not know how all this should be done in MySQL... Sorry about that...

one-to-one and one-to-many relationships

Using Mysql Workbench, I found that the sql of the one_to_one table and one_to_many table is similar. Both use a non-unique foreign key to implement their relationships.
CREATE TABLE IF NOT EXISTS `mydb`.`one_to_one` (
`id` INT NOT NULL,
`parent_id` INT NOT NULL,
PRIMARY KEY (`id`, `parent_id`),
INDEX `fk_one_to_one_parent1_idx` (`parent_id` ASC),
CONSTRAINT `fk_one_to_one_parent1`
FOREIGN KEY (`parent_id`)
REFERENCES `mydb`.`parent` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
Consequently, I can insert rows in the one_to_one table that reference the same row in the parent table just like the one_to_many table.
Is not this a violation to the one-to-one relationship? Or should I define the one-to-one relationships with a unique foreign key?
Foreign key constraint only checks if a value of parent_id column in table one_to_one exists in parent table or not.
You can handle the issue by adding an unique index for parent_id in one_to_one table.
ALTER TABLE `mydb`.`one_to_one`
ADD UNIQUE INDEX `parent_id_UNIQUE` (`parent_id` ASC);

MySQL -- create two indexes, only one appears in SHOW CREATE TABLE output

In have a many-to-many linking table and I'm trying to set up two foreign keys on it. I run these two statements:
ALTER TABLE address_list_memberships
ADD CONSTRAINT fk_address_list_memberships_address_id
FOREIGN KEY index_address_id (address_id)
REFERENCES addresses (id);
ALTER TABLE address_list_memberships
ADD CONSTRAINT fk_address_list_memberships_list_id
FOREIGN KEY index_list_id (list_id)
REFERENCES lists (id);
I would expect that when I run SHOW CREATE TABLE address_list_memberships I'd see this:
[...]
KEY `index_address_id` (`address_id`),
KEY `index_list_id` (`list_id`),
CONSTRAINT `fk_address_list_memberships_list_id` FOREIGN KEY (`list_id`)
REFERENCES `lists` (`id`),
CONSTRAINT `fk_address_list_memberships_address_id` FOREIGN KEY (`address_id`)
REFERENCES `addresses` (`id`)
But instead I get this:
[...]
KEY `index_list_id` (`list_id`),
CONSTRAINT `fk_address_list_memberships_list_id` FOREIGN KEY (`list_id`)
REFERENCES `lists` (`id`),
CONSTRAINT `fk_address_list_memberships_address_id` FOREIGN KEY (`address_id`)
REFERENCES `addresses` (`id`)
It looks as though only one index is there. Seems to contradict the MySQL docs which say MySQL automatically creates an index on the referencing column whenever you create a foreign key.
I've noticed this only-one-index thing every time I create two FKs on a table whether I use a GUI tool such as CocoaMySQL or SQLyog, or whether I do it on the command line.
Any illumination of this mystery would be very much appreciated.
I just tried it and it works fine for me. I copied and pasted the ALTER statements you wrote and here is what I get:
mysql> show create table address_list_memberships;
CREATE TABLE `address_list_memberships` (
`address_id` bigint(20) unsigned NOT NULL,
`list_id` bigint(20) unsigned NOT NULL,
KEY `index_address_id` (`address_id`),
KEY `index_list_id` (`list_id`),
CONSTRAINT `fk_address_list_memberships_list_id`
FOREIGN KEY (`list_id`) REFERENCES `lists` (`id`),
CONSTRAINT `fk_address_list_memberships_address_id`
FOREIGN KEY (`address_id`) REFERENCES `addresses` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
I'm using MySQL 5.0.51a on Mac OS X.
edit: Try the following query to get all the indexes MySQL thinks exist on your table:
SELECT * FROM information_schema.key_column_usage
WHERE table_schema = 'test' AND table_name = 'address_list_memberships'\G
(I used the 'test' database for my test; you should replace this string with the name of the schema where your table is defined.)
It doesn't really matter. You still have an index on list_id. MySQL requires any foreign key constraint to also have an index on the referencing fields. Since both index_list_id and fk_address_list_memberships_list_id are built on list_id, MySQL probably sees this and uses index_list_id as the index, renaming it to fk_address_list_memberships_list_id. You could even skip declaring the index, since MySQL will do it implicitly in the version you are using.