Implement Foreign Key in mysql table - mysql

Im trying to restore some old database tables, that when i build them i did not user foreign keys. I have the field that corresponds to the Foreign Key, but i've not set it up in the relations table to which table it connected.
Right know i have a problem because if i try to add that relation, it cannot, because there are some rows deleted in the other table.
Is there any mysql command for checking this type NULL relations for me to delete the rows that i dont need.. and in the end.. add the relation.
TableA
id,
name
TableB
id,
tableA_id,
points
I've deleted some TableA rows.. now i cannot had that relation.
Any mysql command to help, or need to check manually?
Thanks

Assuming that you have PRIMARY KEY constraint at least on TableA.id you can try
-- Delete all orphaned records from TableB
DELETE b
FROM tableb b LEFT JOIN tablea a
ON b.a_id = a.id
WHERE a.id IS NULL;
-- Create a FK constraint
ALTER TABLE TableB
ADD CONSTRAINT fk_a_id FOREIGN KEY (a_id) REFERENCES tablea(id);
Here is SQLFiddle demo

Related

How to make a relation between two tables without foreign key

I'm a total newbie and I'm trying to do a mysql database, using xampp for linux 1.8.1.
I want to make a relation between two tables A and B. For what I know foreign keys create a bijection, or a one-to-one relation. I must not have such a strict relation, so I only created a column inside table A that stores the id of table B.
Is this correct? There's not a way to enforce it? I mean, this way you could delete a row of table B that is referenced in table A. you could store a value inside A that doesn't correspond to an id of any row of B. How to prevent this?
The main problem for me is to prevent deletion of a row of table B if the row id is referenced by a row of table A.
create table table_b (
b_id integer primary key
);
create table table_a (
b_id integer primary key references table_b (b_id)
);
insert into table_b values (1);
insert into table_a values (1);
The following statement will fail.
delete from table_b where b_id = 1;
If you'd built that with PostgreSQL, the error message would say
ERROR: update or delete on table "table_b" violates foreign key constraint "table_a_b_id_fkey" on table "table_a" Detail: Key (b_id)=(1) is still referenced from table "table_a".
That structure gives you a "1 to 0 or 1" relationship between the two tables. For "1 to 0 or many", add one or more columns to table_a's primary key.
create table table_b (
b_id integer primary key
);
create table table_a (
b_id integer references table_b (b_id),
checkout_date date not null default current_date,
primary key (b_id, checkout_date)
);
That structure will let table_a store multiple rows for one value of b_id, but each of those rows must have a different checkout_date.
I think you allways need an primarykey for this, or you write a trigger who checks the consistence of ID from B when a change occurs.
I dont know that it would be possible without a trigger or a constraint ...

how to update a primary key if it is also the foreign key to another table?

I have a table, tableA, which has a column myID. myID is a primary key in tableA and foreign key to tableB.
when i tried to update a particular record's myID in tableA:
update tableA
set myID = 123456
where myID= 999999
i got this error:
The UPDATE statement conflicted with the FOREIGN KEY constraint
"tableA_FK00". The conflict occurred in database "mydatabase" , table
"tableA" , column 'myID'.
i had set myID's Update Rule to 'Cascade' and Enforce Foreign Key Constraint to 'No' but i still cannot update. how should i proceed?
If there's a record in tableB that references tableA with PK 123456 and tableB is the table with the "tableA_FK00" constraint then you are violating the constraint. If you must change the PK of a row in tableA (and I'm not sure why you're doing that, PK's should never change!!!) you have the burden of making sure no other records reference it with FK constraints.
So if you insist on changing the PK in tableA:
Find which table has the constraint "tableA_FK00" (ensure it's only tableB see post here).
Temporarily remove the constraint in tableB
Update tableA
Update all rows in TableB that need their FK changed
Reapply FK constraint on tableB
Another option:
Insert all ids of rows from tableB with FK 123456 into a temp table (this table just has the keys of PK's from tableB)
Set tableB FK field to allows nulls
Set all fields in tableB FK = null by joining with the temp table on tableB PK
Change the row in tableA
Set all the rows in tableB to 999999 by joining with the temp table.
Try these steps:
Disable FK constraints temporarily (ALTER TABLE tableA WITH NOCHECK
CONSTRAINT ALL).
Update your Primary Keys
Update your Foreign Keys to match the Primary Keys change
Enable back enforcing FK constraints

mysql foreign key update constraint in a transaction?

I can not find official mysql explanation about this, so I wanna throw it here.
If I have foreign key constrains between two tables in MySQL, say tableA is the parent table, tableB is the child table. And, on parent tableA, I will use "ON UPDATE CASCADE ON DELETE CASCADE" to make sure actions of update/delete can be applied to child tableB by MySQL automatically.
Now, my question is: if the update to child table and parent table is in a transaction or not?
Or by using the following statements, any differences?
Method 1:
UPDATE tableA SET col1="A" and col2="B";
Method 2:
Begin;
UPDATE tableA SET col1="A" and col2="B";
Commit;
Now, I met the problems in method1: when tableA is updated, tableB might take very long to update its corresponding columns(not in a transaction for sure).
Anyone met similar problems before?
Assuming all of your tables are using InnoDB, then almost all actions you do while in a transaction are covered by that transaction and can be rolled back. Somethings, like DROP TABLE do an implicit commit. But for select/update/insert/delete, it's all covered.
That includes any inserts/updates/deletes that are triggered by a foreign key cascade relationship.
say tableA is the parent table, tableB is the child table. And, on
parent tableA, I will use "ON UPDATE CASCADE ON DELETE CASCADE" to
make sure actions of update/delete can be applied to child tableB by
MySQL automatically.
If tableA has ON UPDATE CASCADE ON DELETE CASCADE, then tableA is the "child", not the "parent". (SQL doesn't use the terms "parent" and "child"; tableA is the referencing table, and tableB is the referenced table.) Changes to the referenced column in tableB will automatically be applied to matching values in tableA.
create table tableB (
column_a char(2) primary key
);
create table tableA (
column_a char(2) not null
references tableB (column_a)
on update cascade
on delete cascade,
column_b char(2) not null,
primary key (column_a, column_b)
);
insert into tableB values ('aa');
insert into tableA values ('aa', 'bb');
update tableB
set column_a = 'cc'
where column_a = 'aa';
select *
from tableA;
column_a column_b
--
cc bb
An update that cascades because of foreign key references is a single transaction. SQL has to work that way. If the update were two transactions--one for the referenced table and one for the referencing table--and the update to the referencing table failed, it would leave the database in an inconsistent state. (For example, in the update above, because 'aa' would have changed to 'cc' in tableB, but not in tableA. The dbms can't let that happen.)

MySQL Multi-Delete. Is it possible to multi-delete referenced rows?

If I have a parent table and a child table, is it possible to multi-delete the rows in them without having a "ON DELETE CASCADE" constraint?
In this example:
create table a(id int primary key);
create table b(id int primary key, a_id int,
constraint fkb foreign key (a_id) references a(id));
Is it not possible to do something like this in order to delete rows in tables a and b? :-(
delete a, b
from b
inner join a on a.id = b.a_id
where a.id = ?;
Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint fails
(`erasmusu6`.`b`, CONSTRAINT `fkb` FOREIGN KEY (`a_id`) REFERENCES `a` (`id`))
I would like to multidelete rows but not to set a "ON DELETE CASCADE" constraint. Also I need to filter the DELETE command with a WHERE clause. Is this possible or should I have to make as many DELETEs as tables in the multidelete?
I solve the problem with optimizer hints, by specifying the exact join order in the DELETE command:
delete a, b
from b
STRAIGHT_JOIN a on a.id = b.a_id
where a.id = ?;
MySQL will DELETE b rows first thanks to the optimizer hint STRAIGHT_JOIN.
This is the note from mysql documentation page (http://dev.mysql.com/doc/refman/5.0/en/delete.html):
"If you use a multiple-table DELETE statement involving InnoDB tables for which there are foreign key constraints, the MySQL optimizer might process tables in an order that differs from that of their parent/child relationship. In this case, the statement fails and rolls back. Instead, you should delete from a single table and rely on the ON DELETE capabilities that InnoDB provides to cause the other tables to be modified accordingly."
So, this implies that you are forced not to use multi delete option!
Hope that helps..

SQL auto-cleanup with 0..1:1..n tables in MySQL

I'm writing an application that requires all users to access data on a central database using MySQL, and I was wondering something.
Let's say I have this setup.
CREATE TABLE A
(
id INT PRIMARY KEY AUTO_INCREMENT,
data INT NOT NULL;
);
CREATE TABLE B
(
id INT PRIMARY KEY AUTO_INCREMENT,
a_id INT,
FOREIGN KEY (a_id) REFERENCES A(id) ON DELETE SET NULL
);
Now, the way I want this set up is, table A must ALWAYS be referenced by a row in table B. However, a row in table B may or may not reference a row in table A. The relationship is 1:n in that multiple rows in table B can reference a single row in table A. I am just wondering if it is possible to have the MySQL database automatically delete a row in A if it is no longer referenced by any row in table B.
The idea here is that I can simply set a_id in table B to NULL and have the database cleanup whatever is left. I guess that's similar to Java garbage collection now that I think about it. If there is no key to automatically enforce the constraint, would a trigger executed after an update work?
EDIT: Adding in the additional relationship constraint.
Run the following query at a specific interval:
DELETE tableA
FROM tableA LEFT JOIN tableB B ON A.id = B.a_id
WHERE B.a_id IS NULL;
Or, to maintain real-time consistency, you could create an OnChange trigger on tableB that performs similar.
Is there a reason for the table structure you are using? The way you are using foreign keys looks backwards to me. Instead of placing your key in table B, you could move it to table A.
This would give you a structure that looked more like:
tableA columns tableB columns
id
b_id id
[values] [values]
fk: a.b_id=b.id
A record added to table A would require a corresponding field in table B, but B would be free to have no values in table A. Then if you wanted to clean out the values in table A, you could simply use:
delete from tableA where b_id=[recordIdToNull];
You could even set A's foreign key up to cascade actions taken on B, so any values deleted from B would also delete the corresponding rows in A.