SQL simultaneously transforming foreign key? (MySQL 5.5) - mysql

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);

Related

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...

Correct way to remove entry from a SQL table along with the relations

If we have TableA and TableB related by TableAB where TableAB has foreign keys for the first two table, then what's the go-to way of deleting an entry from TableA? Up to now if used a property such as IsActive with a bit to describe if the entry is still valid. However, that makes it a little problematic when there are "ghost entries" in the relation tables, such as TableAB.
How should I proceed?
One chaining table in question.
CREATE TABLE EntradaContadorCliente (
ClaveECC int AUTO_INCREMENT not null,
ClaveCliente int not null,
ClaveContador int not null,
ClaveEntrada int not null,
PRIMARY KEY (ClaveECC),
FOREIGN KEY (ClaveCliente) REFERENCES Cliente(ClaveCliente),
FOREIGN KEY (ClaveContador) REFERENCES Contador(ClaveContador),
FOREIGN KEY (ClaveEntrada) REFERENCES EntradaBitacora(ClaveEntrada)
);
Since TableA and TableB related by TableAB; which means TableAB is a chaining table. One way is to use ON DELETE CASCADE for cascading the delete operation on primary table.
Alternative is to, manually delete the entries from your chaining table once the entry has been deleted from primary table.
You can use a ALTER statement to re-create the FK constraint like
ALTER TABLE `TableAB` DROP FOREIGN KEY FK_KEY_Test;
ALTER TABLE `TableAB` ADD CONSTRAINT FK_KEY_Test FOREIGN KEY ('some_column')
REFERENCES `TableA` ('Test_column1') ON UPDATE CASCADE ON DELETE CASCADE;
From MySQL Documentation:
CASCADE: Delete or update the row from the parent table, and
automatically delete or update the matching rows in the child table.
Both ON DELETE CASCADE and ON UPDATE CASCADE are supported.
first you disable all foreign key with:-
alter table table_name
nocheck constraint fk_constraint
then you delete data in parent table.

error with alter table and foreign key

I have 2 tables :
Installers (Fields: id,company,country,experience,name)
Contacts (Fields: name,phone,address)
I would like to match both names, thereby I could click in one value of the name of Installers and it could show me the values of Contacts table.
However when I am trying to set up the foreign key (my child table will probably be Installers , as I have more tables like that and Contacts would be the parent.) It states this error:
query SQL:
ALTER TABLE `Installers`
ADD FOREIGN KEY (`name`)
REFERENCES `SOLAR_PV`.`Contacts`(`name`)
ON DELETE CASCADE ON UPDATE CASCADE;
MySQL ha dicho: Documentación
1452 - Cannot add or update a child row: a foreign key constraint
fails (SOLAR_PV.#sql-32a_183, CONSTRAINT #sql-32a_183_ibfk_1
FOREIGN KEY (name) REFERENCES Contacts (name) ON DELETE CASCADE
ON UPDATE CASCADE)
Both tables are InnoDB and Contacts.name is indexed as well as Installers.name
Primary Key of Installers is id and Primary Key of Contacs is name.
Any idea about what would be the problem?
It seems your child table contains few records those don't have in master, you can check it by below query-
SELECT id FROM Installers ins
LEFT JOIN SOLAR_PV.Contacts cnt ON ins.name=cnt.name
WHERE cnt.name IS NULL;
Note: Assuming name is int type for better performance as it is primary key in one table.
If you get few records by above query then you can follow below 2 approach-
Approach1: You can either delete these records in child table or insert in master table also and then you can create relationship by this alter command.
Approach2: If you don't want to change in your tables existing data and still want to execute your alter query then use as per below-
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE `Installers`
ADD FOREIGN KEY (`name`)
REFERENCES `SOLAR_PV`.`Contacts`(`name`)
ON DELETE CASCADE ON UPDATE CASCADE;
SET FOREIGN_KEY_CHECKS=1;

MySQL "Incorrect index name..." error (unique foreign key)

I keep getting an error "Incorrect index name 'f7'" using MySQL and I've narrowed it down to the following:
First I create the table,
CREATE TABLE testTable (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
f7 INTEGER NOT NULL,
FOREIGN KEY (f7) REFERENCES testTable2 (id) ON DELETE CASCADE ON UPDATE CASCADE,
) ENGINE=InnoDB;
And then elsewhere,
ALTER TABLE testTable ADD UNIQUE f7;
This has led me to believe that this has to do with a duplicate index (?) I just can't figure out how to fix it. Many thanks.
Give it a name, so it doesn't conflict with the foreign Key index
ALTER TABLE `testtable` ADD UNIQUE INDEX `foo` (`f7`);
An incorrect index name error is given when you're attempting to create a new index with the same name as an existing index.
In MySQL, when you create a foreign key, as you're doing with FOREIGN KEY (f7) REFERENCES testTable2 (id) ON DELETE CASCADE ON UPDATE CASCADE, an index is auto-created as well. In this case, the name is defaulted to f7.
The foreign key is created as a non-unique index; your second command: ALTER TABLE testTable ADD UNIQUE (f7); will make this index unique - not add a second one.
To verify what indexes already exist on the table, you can use the following:
SHOW INDEXES FROM testTable;
If you're receiving this error, there is likely additional code elsewhere that is attempting to create an index named f7. You can attempt to find it, or change your CREATE TABLE syntax to name the key something different so that it doesn't cause conflicts:
FOREIGN KEY fk_testTable_f7 (f7) REFERENCES testTable2 (id) ON DELETE CASCADE ON UPDATE CASCADE
In this example, I used fk_testTable_f7 and you should now have a non-unique index on the table named fk_testTable_f7. To make it unique, you can use your existing ALTER command as you want the column to be unique - not the foreign key itself.

MySQL: delete a row ignoring foreign key constraint

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;