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.
Related
I have a foreign key that references two columns in a child table. Id like to delete the foreign key but mySQL just hangs and nothing happens:
Here is the output from SHOW CREATE TABLE table_name:
KEY FK_animal_index (animal_type,food_index),
CONSTRAINT FK_animal_index FOREIGN KEY (animal_type, food_index)
REFERENCES animal_schedules (animal_type, food_index)
ENGINE=InnoDB
I have tried deleting this foreign key using:
`ALTER TABLE table_name DROP FOREIGN KEY FK_animal_index;`
`ALTER TABLE table_name DROP FOREIGN KEY animal_type;`
ALTER TABLE section_configuration DROP FOREIGN KEY FK_animal_index,
DROP KEY (animal_type, food_index);
AND
ALTER TABLE section_configuration DROP FOREIGN KEYFK_animal_index, ADD CONSTRAINT FK_animal_type FOREIGN KEY (animal_type) REFERENCESanimal_schedules(animal_type) ON DELETE SET NULL;
Others have mentioned that ON DELETE not being set can prevent you changing key values (mySQL will reject the change if ON DELETE is not set to anything)
But to no avail, mySQL just hangs and 30 minutes later still nothing. The database is very small at the moment so removing the FK should be fast.
The answer to this question was not about primary keys at all.
I had to stop my program from accessing the table in order to make modifications to it.
In mySQL db, you can add tables and add columns at any time, but if you want to change a column or remove a column, it must not be in use by any program or it will hang indefinitely.
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...
Why does Mysql/InnoDB seem to rename some of the foreign keys I create?
e.g.
mysql> alter table JOB_LISTENER add foreign key FK_JOBS (job_id) REFERENCES job(id);
mysql>
mysql> show create table JOB_LISTENER;
snip> ....
mysql> CONSTRAINT `JOB_LISTENER_ibfk_4` FOREIGN KEY (job_id) REFERENCES job (id)
snip> ....
it renames the foreign key i created named FK_JOBS to JOB_LISTENER_ibfk_4 - any ideas why it does that?
Many thanks,
Sean
You must use the CONSTRAINT keyword to name a constraint:
mysql> ALTER TABLE JOB_LISTENER ADD CONSTRAINT FK_JOBS FOREIGN KEY (job_id)
REFERENCES job(id);
This automatically names the index to the same name, if it needs to create an index.
mysql> SHOW CREATE TABLE JOB_LISTENER\G
*************************** 1. row ***************************
Table: JOB_LISTENER
Create Table: CREATE TABLE `JOB_LISTENER` (
`job_id` int(11) DEFAULT NULL,
KEY `FK_JOBS` (`job_id`),
CONSTRAINT `FK_JOBS` FOREIGN KEY (`job_id`) REFERENCES `job` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
http://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html says:
If the CONSTRAINT symbol clause is given, the symbol value, if used, must be unique in the database. A duplicate symbol will result in an error similar to: ERROR 1022 (2300): Can't write; duplicate key in table '#sql- 464_1'. If the clause is not given, or a symbol is not included following the CONSTRAINT keyword, a name for the constraint is created automatically.
Sometimes you have to read between the lines. In the above paragraph, I infer from the last sentence that you must use the CONSTRAINT keyword to give a name for the constraint, because if you don't, then the constraint name is created automatically.
Tip: Be aware that constraint names must be unique within the database, not only within the table. Go figure, this is part of the SQL standard. So you may not expect this, so be careful not to use duplicate constraint names.
Whereas in some implementations you can use the same index name in multiple tables in the same database (the SQL standard does not cover index implementation, as a_horse_with_no_name reminds me).
I use MySQL with InnoDB engine. I double-checked type of columns. But always have:
Error Code: 1215. Cannot add foreign key constraint
I tried:
ALTER TABLE `mail`.`boxes`
ADD CONSTRAINT FK_id
FOREIGN KEY (id)
REFERENCES `mail`.`users` (id)
ON UPDATE NO ACTION
ON DELETE NO ACTION;
and
ALTER TABLE `mail`.`boxes`
ADD FOREIGN KEY (id)
REFERENCES `mail`.`users` (id)
Nothing works(((
Please, help, what I am doing wrong (except choosing MySQL :-) )?
If table contains data then you are not able to add foreign key you drop table object and recreate
use below reference for the same
Basics of Foreign Keys in MySQL?
To check what exactly the problem is, use:
SHOW ENGINE INNODB STATUS\G
There is section "last foreign key error". Look at: http://dev.mysql.com/doc/refman/5.0/en/innodb-monitors.html
My guess is that data type od mail.boxes (id) and mail.users (id) is not the same. (E.g. smallint in one table and integer in second one).
Data in table on which you're trying to create FK could possibly also be problem (are your mailbox ids the same as id of existing users?)
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);