In mysql, I've got the following:
TABLE docs (
ID
title
content
)
TABLE specialDocs (
docID -> docs(ID)
userID -> users(ID)
)
So specialDocs is a subset of documents that can belong to users.
I am wondering: Is it possible to specify a cascade rule so that when a user is deleted, the docs that belong to that user are automatically deleted? (I realize it would be simple to do this if the pointer to users(ID) was a column within the table "docs". However I am unclear if it is possible with a join table like the above...)
Thanks in advance for your help
I wouldn't do that - your specialdocs table is a many-to-many table, so multiple users could be related to the same document. What you want, shouldn't be allowed without deleting the other references first - which a cascade delete won't do. And if you don't have referential integrity (IE: MyISAM table), then you'll have orphaned records in specialdocs to a document that no longer exists.
Cascade on delete is a referential integrity feature, so it won't be available for MyISAM tables - you'd have to use a trigger for that. Given the need to check for referential dependencies, I'd use a trigger for Innodb tables as well to get rid of the related specialdocs records first...
Related
At past, I was used to make a table relationship programmatically, which is quite handy since you don't need to make FK constraint to each table which have relation.
But, I wonder what is the differences or the advantages of giving a FK constraint to tables that have relation, instead of just creating an attribute and retrieve them programmatically (calls the tables where field = another table PK).
Just some information, I work on php independent MVC framework without any dependency to eloquent or something else.
Hope someone give me some short lesson on this :D Thank you and have a nice day!
There are certain principles that you should follow while coding and development, I can say that there is no issue whether or not you create a foreign key constraint to a table that has relation or not but you know that won't restrict the column to have only those values that are being referenced by it. So basically it is not a good DB Schema and may lead to inconsistencies. For example deleting a parent table's row you will have to manually delete the child table's row on the other hand if you have a foreign key constraint that to onDelete = cascade, your database will automatically take care of everything and there won't any inconsistencies.
I'm using the PHP Laravel Framework, but it's a general PHP question. Is it safe to use the MySQL foreign key relation on delete cascade to delete related rows ? Or is it a best practice to do it in PHP ? I find the cascade system realy nice but don't know if it's safe to use it ? Any best practices ?
For example when you have a user that have created posts and that user is deleted, do you delete his posts with PHP then delete the user, or just use cascade ?
Thanks for your feedbacks.
Yes, you can rely on CASCADE deletes. If you define a relationship with ON DELETE CASCADE, the foriegn row will definitely be deleted. Using ON DELETE CASCADE is definitely reccommended (assuming you want to delete the related rows), and it is likely more reliable than implementing the delete cascade in your application.
In the example you gave, the rows containing the users posts were related to the user using a foreign key with ON DELETE CASCADE. In this case, you would just delete the user. MySQL will follow all of the relationships and delete all related rows. This wil prevent orphaned data. Doing it via the application is much more "risky" in terms of the potential for orphaning data.
Keep in mind, however, if there are other relationships to the same data (e.g. there are reply posts relating to the user's post who is going to be deleted), the delete can be blocked, since the reference in the reply row would be dangling. Of course, this is all dependent on your database design and how you set up your foreign keys.
I am working on a PHP application which Db design was created by another guy who added FK constraints(On Cascade delete etc) between tables. So far what I am used to do is to put a FK in another table. For instance we have two tables:
Users
ID
Name
CountryID
Countries
ID
Name
At application Level I will create two Separate INSERTs calls. If FK is present, then what change do I need to make at my application level?
You need to make sure that the row you reference with the FK exists before you create the row in the other table.
… but you are probably doing this already as that is the logical order to create the rows.
Foreign keys enforce referential integrity.
These constraints guarantee that a row in a table order_details with a field order_id referencing an orders table will never have an order_id value that doesn't exist in the orders table.
Foreign keys aren't required to have a working relational database (in fact MySQL's default storage engine doesn't support FKs), but they are definitely essential to avoid broken relationships and orphan rows (ie. referential integrity). The ability to enforce referential integrity at the database level is required for the C in ACID to stand.
I am working with mysql and codeigniter using the redbean ORM. After implementing a foreign key for many to many assosciation I got the following error when I run:
drop TABLE IF EXISTS `temp`
Integrity constraint violation: 1217 Cannot delete or update a parent row: a foreign key constraint fails thrown
I then entered SHOW ENGINE INNODB STATUS into phpmyadmin. The output includes:
LATEST FOREIGN KEY ERROR------------------------: Cannot drop table `db1`.`temp`because it is referenced by `db1`.`temp_workers`.
In other words another table references the FK. For testing purposes I think the best thing to do is to drop all the associated tables and recreate them using the controller I'm testing. Is this the best way to go? I've tried:
drop TABLE IF EXISTS `temp` `temp_workers`
, but I'm still getting the above error, and the drop command does not work. Also:
truncate TABLE `temp`, `temp_workers`
gives:
You have an error in your SQL syntax
As mentioned in the comments you have to drop any tables with FK contraints to other tables, first, then you can drop the tables being linked to.
Example:
User
id: 1
name: Mike
Address
id: 1
user_id: 1 (FK constraint to User.id table.column)
address_1: 555 Main Street
This setup is a 1:1 relationship (more on data normalization), where one user row can reference one address row, and because the address row is dependent upon the existence of the user row, if you attempt to remove the user row, you will see the errors you mentioned.
But if you drop the Address table first, everything works as expected because the User table is not FK to any other table.
Ensuring referential integrity within your schema ensures you do not end up with orphaned rows, which will permeate throughout your data driven application.
You could also issue the following commands:
SET foreign_key_checks = 0;
# Do Stuff
SET foreign_key_checks = 1;
But I would strongly advise against this, as you could break the referential integrity of your data, and end up in a real mess. I've seen someone do this in an enterprise environment and it took them weeks to clean it up. However, if you are doing this STRICTLY for testing purposes; like writing unit tests, or just learning, and you didn't want to drop the tables every time, you could do this:
# Because we remove the foreign key check, we can truncate in any order
SET foreign_key_checks = 0;
TRUNCATE TABLE user;
TRUNCATE TABLE address;
SET foreign_key_checks = 1;
Proper schema design using foreign key constraints goes along way to building a good foundation for any data driven application. It will take time to get your head around when to use, and how to construct foreign key constraints, but over time you will begin to understand. A good way to get started is to download an open source project like magento, wordpress, or vbulletin and take a look at their schemas. You can even introspect these schemas using MySQL workbench and view their Entity-Relationship Diagrams (ERDs), which will visually demonstrate links between tables.
I have two different kinds of document. One is organized by folder. The other is organized by client. Here is the table structure, in mysql:
Table docs
ID
title
Table folderDocs
docID -> docs(ID)
folderID -> folders(ID) ON DELETE CASCADE
Table clientDocs
docID -> docs(ID)
clientID -> clients(ID) ON DELETE CASCADE
I am looking for an elegant way to delete documents automatically when either a folder or a client is deleted. The above cascade rules don't quite accomplish this. (Ie the rows in folderDocs will be deleted, but the corresponding rows in docs will remain.)
Is there anyway to set this up in mysql, using cascade rules or some other method, so that when a row from folderDocs or clientDocs is deleted by cascade, the corresponding row in docs is also deleted? (I am hoping to avoid having to programatically delete the documents first, then delete the folder / client.)
Thanks (in advance) for your help.
Assuming that each document must belong to a folder or a client, then you may want to setup a scheduled cleanup job to delete all documents which do not have folders and clients using the query below
DELETE FROM docs USING docs
LEFT JOIN clientDocs c ON (c.docid = docs.id)
LEFT JOIN folderDocs f ON (f.docid = docs.id)
WHERE ISNULL(c.clientid) AND ISNULL(f.folderid)
I do not think you can do that in straight sql. you might need to write a stored procedure to do it.
But is it a good idea. cos the way your tables are designed makes it look like a many to many relationship. can you delete a doc if there are still references to it from a another folder?
If they are suppose to be a one to many relationship, then the foreign key to the folder and the client should be in doc and not a table by itself. then you can use cascade delete.
Edit: you could try using a trigger instead. http://dev.mysql.com/doc/refman/5.0/en/triggers.html
but it still requires that some codes be written (in the form of triggers)