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...
Related
I have a foreign key that was generated with the following command in an old and already deployed migration:
ALTER TABLE `job_template`
ADD COLUMN `parent_id` BIGINT,
ADD FOREIGN KEY fk_job_template_parent_id(parent_id) REFERENCES job_template(id) ON DELETE CASCADE;
Now I am trying to drop this foreign key with following command:
ALTER TABLE job_template DROP FOREIGN KEY fk_job_template_parent_id;
The problem is that this works for mariaDB but not for mySQL and I need a migration that would work in both cases
If I list the SHOW CREATE TABLE command (before the deleting of the foreign key) from both environments I get the following:
mariaDB:
constraint fk_job_template_parent_id foreign key (parent_id) references job_template (id) on delete cascade,
mysql:
constraint job_template_ibfk_5 foreign key (parent_id) references job_template (id) on delete cascade,
The constraint names are different in the 2 environments, and thus I have no way to write a migration that would consistently drop this foreign key.
Is there any way to get around this situation?
Your problem is that you are not explicitly naming your constraints. This leaves each database to pick a name for you. The trick here is to name your foreign key constraints explicitly, when you create the actual tables on both MySQL and MariaDB:
CREATE TABLE job_template (
...,
parent_id int NOT NULL,
CONSTRAINT your_constraint FOREIGN KEY fk_name (parent_id)
REFERENCES job_template(id) ON DELETE CASCADE
);
But fixing your immediate situation would require more work. One option would be to query the information schema table, for the table involved, to find out the actual constraint names:
USE INFORMATION_SCHEMA;
SELECT
TABLE_NAME,
COLUMN_NAME,
CONSTRAINT_NAME,
REFERENCED_TABLE_NAME,
REFERENCED_COLUMN_NAME
FROM KEY_COLUMN_USAGE
WHERE
TABLE_SCHEMA = 'your_db' AND
TABLE_NAME = 'job_template' AND
REFERENCED_COLUMN_NAME IS NOT NULL;
This should return one record for every column and constraint. With this information, you should be able to run your current alter statements.
This is easy enough to do using a tool like Java, or something similar. If you want to do this directly from the database, then you would need dynamic SQL, which probably means writing a stored procedure.
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.
I have a table with a natural key and another with a foreign key constaint to it:
create table A
(
id varchar(255) not null primary key
...
)
create table B
(
a_id varchar(255) not null
...
foreign key (a_id) references A (id)
)
I would like to execute a transformation on A.id, (in this specific case lowercasing it) and simulataneously on B.a_id.
Obviously if I do:
update A set id=lower(id);
update B set a_id=lower(a_id);
Than I will get a foreign key constraint violation on the first update.
Is there anyway to execute the two updates "simultaneously", or can you recommend another way to deal with this?
Simplest Approach might be to Drop the constraint,
Perform Update Queries
Again, Introduce the Foreign Key Constraint.
drop the constraint and re-create the constraint with ON UPDATE CASCADE
then execute the update stament on the parent table no child table would get modified.
ALTER TTABLE b ADD CONSTARINT fk_const
FOREIGN KEY(a_id) REFERENCE a (id) ON UPDATE CASCADE
now execute this update
update A set id=lower(id);
so I am working on a few tables and there are some data inconsistency between them... One or two tables have a foreign key constraint on a particular table (call it table X), but that table has multiple rows with the foreign key column.
What I want to do is to remove the duplicated rows in table X, but the foreign key constraint is preventing me from doing this. Is there a way to force delete the rows while ignoring the foreign key constraint since I know what I'm doing?
SET foreign_key_checks = 0;
That will prevent MySQL from checking foreign keys. Make sure to set it back to 1 when you are done though.
Also, you could always drop the foreign key and then add it later if you wanted to only affect a singular key
ALTER TABLE tableName DROP FOREIGN KEY fk;
Simply execute as follows:
Disable foreign key check
SET foreign_key_checks = 0;
Delete your records
DELETE FROM table_name WHERE {conditions};
Enable foreign key check
SET foreign_key_checks = 1;
Credit: https://www.knowledgewalls.com/johnpeter/books/mysql/how-to-ignore-constraints-while-insertupdate-or-delete-records-in-mysql
As some people already pointed out, ignoring a restricting foreign key leaves you with database inconsistencies. Preventing DELETEs is something you want in such cases.
You should better delete depending rows prior to the main query:
DELETE FROM cities WHERE country_id=3;
-- Afterwards you delete rows from the parent table without error:
DELETE FROM countries WHERE country_id=3;
Or, even better, change the foreign key once, so it does the deletion automatically (cascading):
ALTER TABLE cities DROP FOREIGN KEY `fk.cities.country_id`;
ALTER TABLE cities ADD CONSTRAINT `fk.cities.country_id` FOREIGN KEY (country_id)
REFERENCES countries (id) ON UPDATE CASCADE ON DELETE CASCADE;
-- From now on, just delete from the parent table:
DELETE FROM countries WHERE country_id=3;
To expand on the accepted answer, you have to specify the constraint name after DROP FOREIGN KEY
You can check the constraint name by issuing SHOW CREATE TABLE.
> SHOW CREATE TABLE tbl_name
Create Table: CREATE TABLE `tbl_name` (
`id` int(11) DEFAULT NULL,
`foo_id` int(11) DEFAULT NULL,
CONSTRAINT `foo_ibfk_1` FOREIGN KEY (`foo_id`)
)
In this case, "foo_ibfk_1" is the constraint name. So you can write:
ALTER TABLE tableName DROP FOREIGN KEY foo_ibfk_1;
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.