Referential integrity sql - sql

i hope you can help me with a general question about referential integrity.
If i am deleting data in a table that is referenced to another table as a foreign key.
How can i delete the data without violating the referential integrity?
Do i have to erase the foreign key or do i replace the reference with some sort of placeholder.
Kindest David
Research in web but could not find any useful data

Typically you'd remove the dependent rows first and then delete the parent row.
Say you have a database where users post messages and others comment on those posts. So you have a posts table and a comments table. Now you want to delete all posts of 2018. This means you must first delete the comments to those posts and then the posts:
delete from comments where post_id in
(select post_id from posts where extract(year from post_date) = 2018);
delete from posts where extract(year from post_date) = 2018;
commit;
In many DBMS you can create the foreign keys with an ON DELETE CASCADE clause. That means you'd just delete the posts and the DBMS would go down the whole tree to delete from bottom up. But beware: with many dependent tables and maybe many levels (parent -> children -> grandchildren -> ...) this can be a lot of work. You seem to delete one row, but behind the scenes it may be billions of rows from many tables, and the statement may even time out. So use this clause in small databases, if you like, but be careful with bigger databases, where you may want to delete manually as shown above.

Related

How do I automatically delete all associated components while deleting a product in a SQL relational database?

Is this possible?
If so, does it happen automatically or do I need to config the definition of the foreign key in the component table properly?
The foreign key(s) would need to be defined as ON DELETE CASCADE in order for this to occur. Generally I'd recommend against such a setting because can you imagine (say) deleting a row from your GENDER table and suddenly discovering that half of the millon rows in your CUSTOMER table just vanished, and similarly half of the 100 million rows in your CUSTOMER_SALES tables also went.... That's a career limiting move.
If the foreign keys are not defined as ON DELETE CASCADE you could still mine the data dictionary to wor out the relationships in order to build a "delete child before parent" mechanism for those rare scenarios where you might need this

How can I delete records from a table when there are foreign keys that depend on these records?

I have lots of tables that have foreign keyed to a PersonId column. I need to delete a person from the database.
If I do a simple:
DELETE FROM Persons WHERE PersonId=111
I get an error:
Msg 547, Level 16, State 0, Line 1
The DELETE statement conflicted with the REFERENCE constraint "FK_CIPerson". The conflict occurred in database "adb", table "CI", column 'Person_Id'.
I keep going "down the tree" of dependencies and delete from the roots. This has generally worked, until I got to a certain table where it won't let me delete any further. I believe I have to join 2 tables and delete the rows in BOTH tables that have my PersonId in it.
This join joins the tables in the way I want them to be joined:
SELECT *
FROM Table1
INNER JOIN Table2 ON Table1.anId = Table2.someId
This results in a joined table that has the PersonId (from Table2). I now want to delete all the rows where PersonId=111, so I need a where clause plonked in too.
Thanks in advance!
By definition, SQL DELETE statement only affects one table. If you need to cascade delete, you can simplify things by using #paqogomez suggestion: just specify ON DELETE CASCADE option on the foreign key declaration.
There are at least 3 solutions:
ON CASCADE DELETE
(As answered by Gerardo) If the problem is just foreign key constraints, then you can use this and deleting the person will do all the rest. But this may not always work. As usr said, there are some cases in which foreign keys are complex and mangled a bit.
BEFORE DELETE TRIGGER
You can define a trigger and activate it BEFORE DELETE on the person table. In the trigger you can take care of the deletion of dependent rows from other tables. This is similar to the ON CASCADE DELETE, but you have a little more control over how to perform the deletion... this may solve some of those complex problems.
STORED PROCEDURE
You can define a stored procedure with a person_id parameter. The code would be similar to the trigger's. But in stored procedures you can sometimes do some extras, like deactivating foreign keys (not sure about SQL Server though).
DELETION SCRIPT
This is the most powerful, as you can mix DDL and SQL and do all sorts of stuff. But scripts usually have to be run manually, which might not be acceptable in your case.

Laravel 3 - Cascade deletes on many to many relationships

I can't seem to work this out at the moment.
I have 3 tables, interests, interest_user, and users, with a many-to-many relationship setup between them.
If I delete an interest I want to make sure that any records in the pivot table are deleted as well (or else I'm going to run into errors down the line I guess).
Can this be done with $table->foreign() on the interests table (I don't think so because there's no id to reference). Otherwise do I have to loop through all the relationships when the interest is deleted and delete each pivot?
I think I'm going to encounter the same problem on a one-to-many relationship I have
One category has many interests. If I delete a category I don't think I can have a foreign key linked to interests on the category table. I'll also need to cascade a category deletion through to all the interest_user records.
Any guidance would be hugely appreciated as my brain is a little frazzled.
Cheers!
Alex
Many to Many:
According to the Laravel 3 Docs on Foreign Keys, your migration for the pivot table should be:
$table->foreign('user_id')->references('id')->on('users')->on_delete('cascade');
$table->foreign('interest_id')->references('id')->on('interests')->on_delete('cascade');
When you delete either a user or an interest, the rows associated with that user or interested in the pivot table will be deleted.
One to many
If you are dealing with a one-to-many (for example, users and creditcards). on the creditcards table you will have a user_id and to set up foreign key like so:
$table->foreign('user_id')->references('id')->on('users')->on_delete('cascade'); (basically exactly like the many-to-many)
So when you delete the user, the row(s) on the creditcards table associated with that user will be deleted as well.

entity relationship between an actor and a receiver

So I have a SQL relationship problem. Lets say I have a database where I want to keep records of information about individuals. Now I have setup a table to take on that information. Okay so far so good.
Often times duplicate information can be discovered in the table and it would be removed. A record is considered a duplicate if a particular field has the same value as another field in another row. Example: Duplicate emails.
Now I want to create another table in the database to keep track of every duplicate that is ever discovered and deleted. My first thought into this was to create a Foreign Key relationship. So I created and then connected a dupes table to my persons table. The relationship was a simple Foreign to Primary key relationship with an on delete constraint.
Now while that may have worked at first the problem arose that the dupes table was receiving records that were deleted even if they were not deleted because they were dupes. This was a problem because even if I decided to delete a person from the persons table just because I did not like them, they would stored in the dupes table anyway.
Then I thought, why not create a disposition field in the persons table and connect that as a unique or primary key to my dupes table's index foreign key. Well the problem is a unique key must have a unique value so multiple dispositions of dupe or I don't like you would not work. The other option was to make the disposition field a primary key. That has the same problem though.
What would be the right relationship for this problem?
I can think of this implementation: An on delete trigger, with a 'before delete' check. The before delete check would confirm if the record being deleted is a duplicate or not. Not sure what all RDBMS systems support such checks though.
IMO, the theoritical relationship is complicated because the record is supposed to be preserved even after the dupe is deleted.
Foreign Keys are not going to solve this problem. I discovered Triggers and their exactly what I need.

Owner ID type database fields

Suppose you have these tables: RestaurantChains, Restaurants, MenuItems - with the obvious relations between them. Now, you have tables Comments and Ratings, which store the customer comments/ratings about chains, restaurants and menu items. What would be the best way to link these tables? The obvious solutions could be:
Use columns OwnerType and OwnerID in the tables Comments and Ratings, but now I can't add foreign keys to link comments/ratings with the objects they are ment for
Create separate tables of Comments and Ratings for each table, e.g. MenuItemRatings, MenuItemComments etc. This solution has the advantage that all the correct foreign keys are present and has the obvious disadavantage of having lots and lots of tables with basically the same structure.
So, which solution works better? Or is there even a better solution that I don't know about?
Since comments about a menu item are different from comments about a restaurant (even if they happen to share the same structure) I would put them in separate tables and have the appropriate FKs to enforce some data integrity in your database.
I don't know why there is an aversion to having more tables in your database. Unless you're going from 50 tables to 50,000 tables you're not going to see a performance problem due to large catalog tables (and having more, smaller tables in this case should actually give you better performance). I would also tend to think that it would be a lot clearer to understand when dealing with tables called "Menu_Item_Comments" and "Restaurant_Comments" than it would to deal with a table called "Comments" and not knowing what exactly is really in it just by the name of it.
How about this alt text http://www.freeimagehosting.net/uploads/8241ff5c76.png
Have a single Comments/Rating table for all the objects and dont use automatically generated foreign keys. The key in the ratings table eg RatingID can be placed in a field in Restaurant, Chain, Menuitems table and they can all point to the same table, they are still foreign keys.
If you need to know in reverse what object the review relates to you would need to have a field specifying the type of review it was, but that should be all.
Use a single table for comments and use GUID's as primary keys for your entites.
Then you can select comments without even knowing beforehand where they belong to:
SELECT CommentText
FROM Comments c, Restaurants r
WHERE c.Source = r.Id
SELECT CommentText
FROM Comments c, Chains ch
WHERE c.Source = ch.Id
etc.
You can't use foreign keys for comments, of course, but it's not that comments cannot live without foreign keys.
You may clean orphaned comments in triggers but there's nothing bad if some of them are left.
You amy also create a global Entity table (with a single GUID column), make your Chains, Restaurants, MenuItems and Comments refer to that table with a FOREING KEY ON DELETE CASCADE, and when DELETE'ing, say, a restaurant, delete it from that table instead. It will delete both a restaurant and all comments on it, and you still have your integrity.
If you want to take advantage of foreign key constraint and normalize the attributes of comments (and ratings) across base tables, you may need to create relationship tables between base tables and comments (and ratings).
e.g. for Restaurants and Comments:
Restaurants
id (PK)
(attributes of restaurants...)
RestaurantComments
id (PK)
restaurantid (FK to Restaurants)
commentid (FK to Comments)
Comments
id (PK)
(attributes of comments...)