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.
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.
Now I have one table "comments" with 'user_id' column as foreign key. This column have a constraint - ON UPDATE CASCADE, ON DELETE CASCADE.
First (bad) way is to remove constraints for 'user_id' column. In that case we loosing connection with 'users' table, but all code stay same.
Second (also not good) way is to create one more table 'anonymous_comments'. New model, new observers, new chapter in admin panel, need to modify code in many places... many work & doubles.
Any better ideas?
If you don't want (or can't for some reason) to do any DB and code modifications, you could create a dummy user 'anonymous' and use it's user_id for anonymous comments.
Let's say you have got two tables like the following in a MySQL database:
TABLE people:
primary key: PERSON_ID,
NAME,
SURNAME, etc.
TABLE addresses:
primary key: ADDRESS_ID,
foreign key: PERSON_ID,
addressLine1, etc.
If you manage the creation of rows (in both table) and the retrieving of data trough PHP do you still need to create a physical relationship in the database? If yes, why?
Yes, one concrete reason is to have faster retrieving of rows if you want to join tables. Creating a foreign key constraint automatically creates a an index on the column.
So table address' schema should look like this, (assuming People's table primary key is PERSON_ID)
CREATE TABLE Address
(
Address_ID INT,
Person_ID INT,
......,
CONSTRAINT tb_pk PRIMARY KEY (Address_ID),
CONTRRAINT tb_fk FOREIGN KEY (Person_ID)
REFERENCES People(Person_ID)
)
Strictly speaking: You don't need to use FK's. careful indexing and well written query's might seem to be sufficient. However FK's and certainly FK constraints are very useful when it comes to securing data consistency (avoiding orphaned data, for example)
Suppose you wrote your application, everything is tested and it works like a charm. Great, but who's to say that you'll be around every time something has to be changed? Are you going to maintain the code by yourself or is it likely that someone else might end up doing a quick fix/tweak or implement another feature down the road? In reality, you're never going to be the only one writing and maintaining the code, and even if you are the only one maintaining the code, you're almost certainly going to encounter bugs as time passes...Foreign keys inform both your co-workers and you that data from tbl1 depends on the data from tbl2 and vice-versa. Just like comments, this makes the application easier to maintain.
Bugs are easier to detect: creating a method deleting a record from tbl1, but forgetting to update tbl2 to reflect the changes made to the first tbl. When this happens, the data is corrupted, but the query that caused this won't result in errors: the SQL is syntactically correct and the action it performs is the desired action. These kind of bugs could remain hidden for quite some time, and by the time this is spotted, god knows how much data has been corrupted...
Lastly, and this is an argument that is used all too often, what if the connection to the DB is lost mid-way through a series of update/delete query's? FK Constraints enable you to cascade certain actions. I haven't actually seen this happen, but I know of anybody who doesn't write code to protect against just such a scenarioDeleting or updating several relational records, but mid-way, the connection with the DB gets cut off for some reason. You might have edited tbl2, but the connection was lost before the query to tbl1 was sent. Again, we end up with corrupted data. FK CASCADE's are very useful here. Delete from tbl1, and set an ON DELETE CASCADE rule, so that you can rest assured that the related records are deleted from tbl2. In the same situation, ON DELETE RESTRICT, can be a fairly useful rule, too.
Note that FK's aren't the ultimate answer to life, the universe and everything (that's 42 - as we all know), but they are a vital part of true relational database-designs.
Referential integrity is an article that you should read and comprehend.
there are two ways
-first one is to handle all the things on coding end manage the things on deleting or updating a record
but when you use foreign key you are enforcing the relation and Db don't allow you to delete records with foreign key constraint especially when you don't want to delete the records related to it there is some situations accrue where you need to do this kind of tasks.
-Second way is to manage things on the Db side. If you have 1-to-many or many-to-many relations in database, foreign keys will be very useful. Also they have some good actions - RESTRICT, CASCADE, SET NULL, NO ACTION those can do some work for you
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)
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...