How to update data in a Many-to-Many linking table? - database

For simplicity’s sake lets assume there’s a Post table and a Tags table (not the actual use case but this will keep it simple)
posts Table
id | title
--------------------------------
1 | Random Text Here
2 | Another Post About Stuff
tags Table
id | tag
--------------------------------
1 | javascript
2 | node
3 | unrelated-thing
posts_tags table
id| post_id | tag_id
--------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 2
A Post can have many Tags and a single Tag could be associated with many Posts.
Web App Assumptions Lets pretend adding/removing a Tag doesn't trigger a single aysnchronous action within the web app against the linking table.
Instead the user would edit the Post (adding or removing any tags already created) then hit Save. The web app would submit JSON including an array of Tags ids associated with the Post to the server which would then process the update request in the code.
For example, post_id=1 is submitted with only tag_id=[1,2] so tag=3 needs to be removed as an association in the linking table.
If a Post or a Tag is deleted, I'd have an ON DELETE CASCADE set on
posts_tags.post_id
posts_tags.tag_id
But what is the best way to update the linking table data in the instance of updating the tags associated with a post?

Option 1:
Get all the Post-Tags for the edited Post 
SELECT * FROM posts_tags WHERE post_id = 1
Determine which tags have been added (and INSERT into linking table)
Determine which tags have been removed (and DELETE from linking table)
Option 2:
Delete ALL tags with the post_id in the linking table
Insert all submitted tags into the linking table
Option 3:
Something I'm not thinking about :)
Would Option 2 have a bigger performance impact on indexes as the table grows?
EDIT:
For clarity, the actual Post and Tag data isn't changed or removed. This is purely about Updating a post's associated tags
The database I'm using is PostgreSQL 9.6

Option 2 would be fine from a performance point of view - much better than option 1, because you have a single operation to delete the old associations, and then a bunch on insert statements. In option 1, you have more queries (your first query to retrieve the associations, and then the deletes if applicable).
As long as your table has an index on post_id, then delete * from posts_tags where post_id = ? will be lightning fast, even on a huge table.
There is an alternative...
posts_tags table
id| post_id | tag_id | version_id
--------------------------------
1 | 1 | 1 | 0
2 | 1 | 2 | 0
3 | 1 | 3 | 1
4 | 2 | 2 | 0
5 | 1 | 1 | 2
6 | 1 | 3 | 2
In this case, you use a versioning mechanism to determine the "current" associations (max(version_id)), so you never have to delete anything - you just insert new rows.
In practice, this is probably no faster, but it does save you that "delete" query.

Related

Issue with new table in oracle

I have to add a new table according to some new requirements, the model currently consists of two tables: DETAIL and SUMMARY.
The relation is that every detail has associated one summary, so now I need to add a new table called SUMMARY_ESP, which has the a FK ( SUMMARY) and two more columns, something like this:
ID | SUMMARY_ID | ESP_ID | PRIORITY_ESP | PTY_ID | PRIORITY_PTY
1 | 123 | 34 | 1 | 122 | 1
2 | 123 | 35 | 2 | 111 | 2
3 | 123 | 30 | 3 | null | null
4 | 1111 | 34 | 4 | null | null
Other tables info:
DETAIL TABLE
ID_DET | AMOUNT | DATE | ID_SUMMARY | EXTERNAL_ID
1 | 1000 | 14/05/2018 | 1111 | 4
2 | 2000 | 18/07/2016 | 1111 | 4
3 | 1200 | 11/07/2017 | 123 | 1
4 | 1300 | 21/09/2018 | 123 | 2
SUMMARY TABLE
ID_SUMMARY | PRIORITY| PROFILE | CLASS | AREA
123 | 1 | 1 | 5 | 3
1111 | 2 | 1 | 5 | 3
33 | 3 | 2 | 5 | 9
4 | 4 | 8 | 5 | 10
So according to this, SUMMARY_ID , ESP_ID and PTY_ID are unique, the thing is at some point to know the what is the ESP_ID of certain detail, but since the relation is with SUMMARY table, I have no idea which one was when it was added, so I was asked to create a new column to the DETAIL table called EXTERNAL_ID, so I can know what is the code from the SUMMARY_ESP.
So if the row is the first one, it can be either 24 or 122 in the new column according to some previous logic, but I'm worried about the implications this might have in the future, because somehow I might be duplicating information, also I would need to make some weird logic in order to get the priority depending on whether it's ESP_ID or PTY_ID.
The new table along with SUMMARY are somehow parameters table, their values do not change that often and only the PRIORITY column would change, DETAIL instead is more transactional, and it has insert and update everyday according to some business logic.
I was thinking of adding the ID of the new table as a FK to the DETAIL table, but at the end would be the same, because it'll be hard to maintain and update would be harder, also it's like a circular dependency, so I'm kind of stuck with this , so any kind of help would be really helpful, below the complete model, with the current idea.
Also I can't add those new columns to the table SUMMARY, because there could be more than one associated to the same code in that table and since it's the PK I cant add two rows with the same code.
The relation is that every detail has associated one summary
You need to represent that relationship in your database layout : if you have a 1-N relationship between SUMMARY and DETAIL, you want to create another column in DETAIL that holds the primary key of the SUMMARY record that it is related to.
With this relation in place, you can start from a DETAIL row, relate a row from SUMMARY and identifiy all SUMMARY_ESP records that are linked to it.
Now if you need to uniquely relate a DETAIL record to a SUMMARY_ESP record, then you want to either add a foreign key to SUMMARY_ESP in DETAIL, or the other way around (add a foreign key to DETAIL in SUMMARY_ESP), depending on the way your data flows.

Database 1:N tables structure, two approaches (one or multiple tables)

Let's assume we have application with pages, posts and events. With each part of this application we want to have comments. Now let's take a look into tables for our DB.
1. One comment table, object and object_id as foreign key
Page/Post/Event has many comments, foreign key object, object_id
comments table
+-------------+-------------+-------------+-------------+
| id | object | object_id | text |
=========================================================
| 1 | Page | 1 | Comment 1 |
+-------------+-------------+-------------+-------------+
| 2 | Post | 1 | Comment 2 |
+-------------+-------------+-------------+-------------+
| 3 | Event | 1 | Comment 3 |
+-------------+-------------+-------------+-------------+
2. Multiple comments tables
Page (Post, Event) has many page comments, foreign key page_id
page_comments table
+-------------+-------------+-------------+
| id | page_id | text |
===========================================
| 1 | 1 | Comment 1 |
+-------------+-------------+-------------+
post_comments table
+-------------+-------------+-------------+
| id | post_id | text |
===========================================
| 1 | 1 | Comment 2 |
+-------------+-------------+-------------+
event_comments table
+-------------+-------------+-------------+
| id | event_id | text |
===========================================
| 1 | 1 | Comment 3 |
+-------------+-------------+-------------+
I have used specific example, but this can apply to any other 1:N tables or even with M:N (tags), but for simple showcase, this should be good.
We should discuss
Performance concerns
Design pros and cons
Initial thoughts
case 1 means less tables in DB, easier to read, reusable application code
case 1 is better when doing query on all comments (would have to use union at case 2)
case 2 is better in regards of normalization (3NF)
case 2 is easier to backup (dump) parts of the system, e.g. pages itself with their comments
case 2 should be better with performance because less rows => faster

Foreign keys from 2 columns of the same table to the same primary key

I have two tables:
users
id | username
--------------
1 | James
2 | John
3 | Jack
4 | Jim
5 | Jane
6 | Jessica
juniors
senior_id | junior_id
-----------------------
1 | 4
1 | 6
2 | 3
4 | 5
Both the senior_id and junior_id refer to the users table's id column.
How do I set it up so that a) it is guaranteed that both senior_id and junior_id exist in users and b) a delete from users will cascade and remove any instances of the deleted id from juniors whether it's a senior_id or junior_id? I.e. deleting Jim in the example above will automatically remove both the first and last record from juniors.
I tried doing this with two separate constraints. But if I set up cascade on both constraints I get a 'may cause cycles or multiple cascade paths' error.
And if I set it on only one constraint then a delete fails (in a case like Jim) because it cascades to only one of the columns and thus then violates the constraint.
I have to be able to do this on SQL Server 2005.
Remove FK constraint.For FK constraint check.Create trigger on table juniors before insert/update.if id do not exists then rollback.Again now create another trigger on table User for DELETE.and in trigger write script to delete all record.since FK do not fulfill your requirement,therefore no point in keeping one extra constraint.
Most importantly I think your table design is bad.Table design should be like Employee-Manager relation table i.e. keep SeniorID in User Table itself.
so many of your problem will vanish .
Also there is no extra cost or complication for any query on this table
id | username SeniorID
--------------
1 | James
2 | John
3 | Jack 2
4 | Jim 5
5 | Jane
6 | Jessica

Best structure for this database?

The Problem: I want to design a website and I need a database for that, however I don't know which structure is better!
What will happen: Users will add some URIs to their favorites.
Possible structures:
Structure one:
TABLE "USERS":
=====================================================================
id | name | last_name | urls
1 | John | Smith | [google.com,stackoverflow.com,yahoo.com,...]
=====================================================================
Structure two:
TABLE "USERS":
=============================================
id | name | last_name
1 | John | Smith
2 | Joe | Roth
==============================================
TABLE "URLS":
==============================================
id | user_id | url
1 | 1 | google.com
2 | 1 | stackoverflow.com
3 | 2 | ask.com
4 | 1 | yahoo.com
5 | 2 | being.com
==============================================
Which structure is best? Thanks in advance!
The second schema (with a foreign key constraint on URLS.user_id) will be easier to manage. A select query will need to use a join and you'll be performing more inserts, but you won't need to perform string parsing to figure out what the urls are (which, with the first schema, you would need for every single select and update).
One of the tables in the production database at my current job has a schema similar to the first case, and it makes my entire department cringe and complain when they have to write code working with it. Yet the table remains, because fixing it would be a massive overhaul. (The table was created by a manager who no longer works here.) If you're creating your schema now, do it right, while you still can.
Absolutely create another table that save urls + user_id. Your first type is not in Normal form.

Relationships Between Tables in MS Access

I'm new in DataBases at all and have some difficulties with setting relationships between 3 tables in MS Access 2013.
The idea is that I have a table with accounts info, a table with calls related to this accounts and also one table with all the possible call responses. I tried different combinations between them but nothing works.
1st table - Accounts : AccountID(PK) | AccountName | Language | Country | Email
2nd table - Calls : CallID(PK) | Account | Response | Comment | Date
3rd table - Responses: ResponseID(PK) | Response
When you have a table, it usually has a Primary Key field that is the main index of the table. In order for you to connect it with other tables, you usually do that by setting Foreign Key on the other table.
Let's say you have your Accounts table, and it has AccountID field as Primary Key. This field is unique (meaning no duplicate value for this field).
Now, you have the other table called Calls and you have a Foreign Key field called AccountID there, which points to the Accounts table.
Essentially you have Accounts with the following data:
AccountID| AccountName | Language | Country | Email
1 | FirstName | EN | US | some#email.com
2 | SecondName | EN | US | some#email.com
Now you have the other table Calls with Many calls
CallID(PK) | AccountID(FK) | ResponseID(FK) | Comment | Date
1 | 1 | 1 | a comment | 26/10
2 | 1 | 1 | a comment | 26/10
3 | 2 | 3 | a comment | 26/10
4 | 2 | 3 | a comment | 26/10
You can see the One to Many relationship: One accountID (in my example AccountID=1) to Many Calls (in my example 2 rows with AccountID=1 as foreign keys, rows 1 & 2) and AccountID=2 has also 2 rows of Calls (rows 3 and 4)
Same goes for the Responses table
Using this table structure:
Accounts : AccountID(PK) | AccountName | Language | Country | Email
Calls : CallID(PK) | AccountID(FK) | ResponseID(FK) | Comment | Date
Responses: ResponseID(PK) | Response
Accounts.AccountID is referenced by Calls.AccountID. 1:n – many calls for one account possible, but each call concerns just one account.
Responses.ResponseID is referenced by Calls.ResponseID. 1:n – many calls can get the same response from the prepared set, but each call gets exactly one of them.
To actually define the Relationships in Access, open the Relationships window...
... then follow the detailed instructions here:
How to define relationships between tables in an Access database

Resources