Laravel 3 - Cascade deletes on many to many relationships - orm

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.

Related

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

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.

Is it possible to implement an any-any relationship only using 2 tables?

I don't know whether my idea below is applicable:
I have 2 tables, namely A and B.
Each row in table A can be associated with zero or more rows of table B.
Each row in table B can also be associated with zero or more rows of table A.
Table A contains (among others) 2 columns AId (as a primary key) and BId (as a foreign key).
Table B also contains (among others) 2 columns BId (as a primary key) and AId (as a foreign key).
A cascade delete rule is also setup for each foreign key relationship in DB and model class.
It means deleting a row of A will also delete rows, associated with it, of B or deleting a row of B will delete rows, associated with it, of A.
Is it practically possible to do this scenario?
No, not if you are following normal form.
many to Many relationships are a hallmark of needing an intersection table.
More info:
So here's an example. question tagging. A tag can be on multiple questions, and a question can have multiple tags. this is a many to many realtionship. You COULD put multiple entries of tagIds in the Question entity's Tag Column. But you lose A LOT by doing this.
You will not have integrity, because it is VERY difficult to maintain whether or not a tag exists in your tag table as well as in the questions tag column.
This also violates normal form, because a single column cannot have multiple values.
You also cannot easily join on that column, since it has multiple values in it.
I'm assuming that by 'any-any' relationship you are referring to 'many-to-many'.
What you describe in your post is not a many-to-many relation. What you describe is two separate one-to-many relations.
You have a one-to-many relation from TableA to TableB via the AId column in TableB. And you have another one-to-many relation from TableB to TableA via the BId column in TableA. Having two one-to-many relationships in opposite direction is not the same thing as having a many-to-many relationship. Take Stefan's tagging example and consider three queries (QId1, QId2 and QId3) and three tags (TId1, TId2 and TId3). Try to express that all QId1, QId2 and QId3 are tagged each with all TId1, TId2 and TId3. You'll realize that you cannot, because you're trying to express 9 relations in only 6 available 'foreign key' fields. A true many-to-many relation requires up to MxN 'links' possible between two tables of size M and N, while your design allows for M+N (not surprising, since your design is M links in one of the 1-to-many relations and another N links in the other 1-to-many relation).
What you need is a join table. So you have an a and b table that each have a primary key. Then you create an ab table that only has 2 columns. Both are a foreign key. One goes to the a table and the other goes to the b table.
Google for "Database Normalization". You will find lots of examples.
It's possible, but you definitely don't want to do it that way.
You can use a comma separated string of identities in one of the tables. Looking up value from that table to the other is of course a major hassle. Looking up values from the the other table is a nightmare.
Using a cascading trigger with this method is of course out of the question. It might be possible by making an update trigger do the work, but the performance for that would be so bad that it's pointless.
To do this efficiently you absolutely need another table for the relations.

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

Designing an SQL Table and getting it right the first time

I currently working on an issue tracker for my company to help them keep track of problems that arise with the network. I am using C# and SQL.
Each issue has about twenty things we need to keep track of(status, work loss, who created it, who's working on it, etc). I need to attach a list of teams affected by the issue to each entry in my main issue table. The list of teams affected ideally contains some sort of link to a unique table instance, just for that issue, that shows the list of teams affected and what percentage of each teams labs are affected.
So my question is what is the best way to impliment this "link" between an entry into the issue table and a unique table for that issue? Or am I thinking about this problem wrong.
What you are describing is called a "many-to-many" relationship. A team can be affected by many issues, and likewise an issue can affect many teams.
In SQL database design, this sort of relationship requires a third table, one that contains a reference to each of the other two tables. For example:
CREATE TABLE teams (
team_id INTEGER PRIMARY KEY
-- other attributes
);
CREATE TABLE issues (
issue_id INTEGER PRIMARY KEY
-- other attributes
);
CREATE TABLE team_issue (
issue_id INTEGER NOT NULL,
team_id INTEGER NOT NULL,
FOREIGN KEY (issue_id) REFERENCES issues(issue_id),
FOREIGN KEY (team_id) REFERENCES teams(team_id),
PRIMARY KEY (issue_id, team_id)
);
This sounds like a classic many-to-many relationship...
You probably want three tables,
One for issues, with one record (row) per each individual unique issue created...
One for the teams, with one record for each team in your company...
And one table called say, "IssueTeams" or "TeamIssueAssociations" `or "IssueAffectedTeams" to hold the association between the two...
This last table will have one record (row) for each team an issue affects... This table will have a 2-column composite primary key, on the columns IssueId, AND TeamId... Every row will have to have a unique combination of these two values... Each of which is individually a Foreign Key (FK) to the Issue table, and the Team Table, respectively.
For each team, there may be zero to many records in this table, for each issue the team is affected by,
and for each Issue, there may be zero to many records each of which represents a team the issue affects.
If I understand the question correctly I would create....
ISSUE table containing the 20 so so items
TEAM table containing a list of teams.
TEAM_ISSUES table containing the link beteen the two
The TEAM_ISSUES table needs to contain a foriegn key to the ISSUE and TEAM tables (ie it should contain an ISSUE_ID and a TEAM_ID... it therefore acts as an intersection between the two "master" tables. It sounds like this is also the place to put the percentage.
Does that make sense?
There are so many good free open source issue trackers available that you should have pretty good reasons for implementing your own. You could use your time much better in customizing an existing tracker.
We are using Bugtracker.NET in the team I work for. It's been customized quite a bit, but there was no point in developing a system from the beginning. The reason we chose that product was that it runs on .NET and works great with SQL Server, but there are many other alternatives.
We can see those entities in your domain:
The "Issue"
"Teams" affected by that issue, in a certain percentage
So, having identified those two items, you can represent that with two tables, and the relationship between them is another table, that could track the percentage impact too.
Hope this helps.
I wouldn't create a unique table for each issue. I would do something like this
Table: Issue
IssueId primary key
status
workLoss
createdby
etc
Table: Team
TeamID primary key
TeamName
etc
Table: IssueTeam
IssueID (foreign key to issue table)
TeamID (foreign key to team table)
PercentLabsAffected
Unless I'm understanding wrong what you're trying to do, you should not have a unique table for each instance of an issue.
Your database should have three tables: an Issues table, a Teams table, and an IssueTeams joining table. The IssueTeams table would include foreign keys (i.e. TeamID and IssueID) that reference the respective team in Teams and issue in Issues. So Issue Teams might have records like (Issue1, Team1), (Issue1, Team3). You could keep the affected percentage of each teams' labs in the joining table.
Well, just to be all modern and agile-y, 'getting it right the first time' is less trendy than 'refactorable.' But to work through your model:
You have Issues (heh heh). You have Teams.
An Issue affects many Teams. A Team is affected by many Issues. So just for the basic problem, you seem to have a classic Many:Many relationship. A join table containing two columns, one to Issue PK and one to Team PK takes care of that.
Then you have the question of what % of teams. There's a dynamic aspect to that, of course, so to do it right, you'll need to specify a trigger. But the obvious place to put it is a column in Issue ("Affected_Team_Percentage").
If I understand you correctly, you want to create a new table of teams affected for each issue. Creating tables as part of normal operations rings my relational database design alarm bell. Don't do it!
Instead, use one affected_teams table with a foreign key to the issues table and a foreign key to the teams table. That will do the trick.