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

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.

Related

Insertion when both sides are mandatory in entity relationship

I am preparing for an exam from databases and there is this one thing that puzzles me. From what I've read both sides of any relationship can be constrained to be NOT NULL. I've seen it in at least 2 books and various articles.
Nobody however explains how to insert values into these tables. As far as I know it is not possible in most databases (with the exception of Oracle) to insert into multiple tables at once. That means that it would be needed to insert into one of the tables first. However at that moment there doesn't exist a corresponding entry in the second table so I cannot reference it which violates the NOT NULL constraint.
Another problem is that it is hard to enforce the relationship from both sides in 1:N or M:N relationship. (I can only think of triggers)
So the question is: Are these relationships really implementable or are they just "theoretical" concept which is not used in real life?
To implement a relationship between two entities (tables) in SQL, the primary key of a table (Table1) is make the foreign key in the other table (Table2). If it’s two way mandatory relationship (NOT NULL for both tables) then the entries should be first inserted in Table1 which has the primary key first and then the entries for the other Table2 containing the primary key of the Table1 as the foreign key should be inserted. Check this link for more details and an example.

Many to many relationship self join SQL Server 2008

Are there any hard and fast rules against creating a junction table out of a table's primary key? Say I have a table with a structure similar to:
In this instance there are a list of items that can be sold together, but should be marked as dangerous. Any one item can have multiple other items with which it is dangerous. All of the items are uniquely identified using their itemId. Is it OK to refer a table to itself in a many-to-many relationship? I've seen other examples on SO, but they weren't SQL specific really.
This is the correct design for your problem, as long as your combinations can only be two-item combos.
In database design a conceptual design that renders a relation in many-to-many form is converted into 2 one-to-many in physical design. Say for example a Student could take one or many courses and a course could have many students, so that's many to many. So, in actual design it would be a Student table, Course table then CourseTaken table that has both the primary key of Student and Course table thus creating 2 one to many relayionship. In your case altough the two tables are one and the same but you have the virtual third table to facilitate the 2 one to many relationship so that to me is still very viable approach.

Store forum subcategories in the same table or in a separate table

I'd like to hear opinions on if it is better to keep forum categories and subcategories in the same table or in two separate tables...
Let's say you have a table ForumCategories. By adding a colum ParentId referencing the PK Id in the same table you could easily keep both the main categories and subcategories in the same table.
Alternatively, you could create a separate table ForumSubCategories and make the Id on that table a FK referencing PK Id column of the ForumCategories table.
Both solutions would work but what are the pros and cons of each solution?
Obviously, this is a more generic question that can apply to many other scenarios I just couldn't come up with a better phrasing in a hurry...
I can't think of any benefits of using 2 tables. Using 2 tables is going to constrain you to a 2 level tree. If you look at things as objects, then subcategories really are just category object. So put them in the same table. The 1 table structure will be simpler to design around and develop queries for.
If you know for sure that your forums will have only 2 levels of categories, then having 2 tables is reasonable.
Though storing categories in one table with foreign key to itself, basically, allows you store a tree of categories with virutally unlimited levels.
If they are the same entity (Category), you can link to itself. The parent would have a null for the parent ID or it could be linked to itself. This limits you to only one level unless you have a second table to handle the many-to-many possible relationships.
They must have the same fields or you're going to have unecessary fields for one or the other type. A separate table is why you would do this because they're not the same.
This is typical for an employee table. The supervisor is another employee record.

multiple tables need one to many relationship

I have a SQL database with multiple tables: A, B, C, D. Entities in those tables are quite different things, with different columns, and different kind of relations between them.
However, they all share one little thing: the need for a comment system which, in this case, would have an identical structure: author_id, date, content, etc.
I wonder which strategy would be the best for this schema to have A,..D tables use a comment system. In a classical 'blog' web site I would use a one-to-many relationship with a post_id inside the 'comments' table.
Here it looks like I need an A_comments, B_comments, etc tables to handle this problem, which looks a little bit weird.
Is there a better way?
Create a comment table with a comment_id primary key and the various attributes of a comment.
Additionally, create A_comment thus:
CREATE TABLE A_comment (
comment_id PRIMARY KEY REFERENCES comment(comment_id),
A_id REFERENCES A(A_id)
)
Do likewise for B, C and D. This ensures referential integrity between comment and all the other tables, which you can't do if you store the ids to A, B, C and D directly in comment.
Declaring A_comment.comment_id as the primary key ensures that a comment can only belong to one entry in A. It doesn't prevent a comment from belonging to an entry in A and an entry in B, but there's only so much you can achieve with foreign keys; this would require database-level constraints, which no database I know of supports.
This design also doesn't prevent orphaned comments, but I can't think of any way to prevent this in SQL, except, of course, to do the very thing you wanted to avoid: create multiple comment tables.
I had a similar "problem" with comments for more different object types (e.g. articles and shops in my case, each type has it's own table).
What I did: in my comments table I have two columns that manage the linking:
object_type (ENUM type) that determines the object/table we are linking to, and
object_id (unsigned integer type that matches the primary key of your other tables (or the biggest of them)) that point to the exact row in the particular table.
The column structure is then: id, object_type, object_id, author_id, date, content, etc.
Important thing here is to have an index on both of the columns, (object_type, object_id), to make indexing fast.
I presume that you are talking of a single comments table with a foreign key to "exactly one of" A, B, C or D.
The fact that SQL cannot handle this is one of its fundamental weaknesses. The question gets asked over and over and over again.
See, e.g.
What is the best way to enforce a 'subset' relationship with integrity constraints
Your constraint is a "foreign key" from your "single comments" table into a view, which is the union of the identifiers in A, B, C and D. SQL supports only foreign keys into base tables.
Observe that SQL as a language does have support for your situation, in the form of CREATE ASSERTION. I know of no SQL products that support that statement, however.
EDIT
You should also keep in mind that with a 'single' comments table, you might need to enforce disjointness between the keys in A,B,C and D, for otherwise it might happen some time that a comment automatically gets "shared" between entity occurrences from different tables, which might not be desirable.
You could have a single comments table and within that table have a column that contains a value differentiating which table the comment belongs to - ie a 1 in that column means it's a comment for table A, 2 for table B, and so on. If you didn't want to have "magic numbers" in the comments table, you could have another table that has just two columns: one with the number and another detailing which table the number represents.
You don't need a separate comment table for every other, one is enough. Every comment will have a unique ID, so you don't have to worry about conflicts.

Do multiple foreign keys make sense?

can it make sense for one table to have multiple foreign keys?
Suppose I have three tables, Table A, Table B and Table C. If I think of the tables as objects (and they are mapped to objects in my code), then both Tables A and B have a many to one relationship with Table C. I.e. Table/object A and B can each have many instances of C. So the way I designed it is that Table C points to the primary key in both Table A and Table B: in other words, Table C has 2 foreign keys (a_Id, and b_Id).
Edit: I forgot to mention also that Table A can have many instances of Table B. So Table B has a foreign key into Table A. If this makes a difference...
I am wondering if this makes sense or is there a better way to do it? Thanks.
This is fine, but note that it only makes sense if a C always has to have both an A and a B as a pair.
If you just want A's to have C's and B's to have C's, but A and B are otherwise unrelated then you should put the foreign key in A and in B and allow it to be nullable.
Update: after clarification it seems you want two separate relationships: an A can have many Cs, and a B can have many Cs, but a C can only belong to one A or one B.
Solution: It's two separate one-to-many relationships, so create two new tables A_C and B_C, and put the foreign keys there. A_C contains a foreign key to A and a foreign key to C. Similarly for B_C.
In your scenario, of two different tables being referenced by a third, this is also fine. I have tables in my databases that have 3-4 or even more foreign keys. This is provided that the entity always requires all of the references to exist.
Many to many relationships are also implemented as a single table with two (or more) foreign keys, so yes, they do make sense in that context.
See this article about implementing this kind of relationship for PHP and MySQL.
If you can't formulate the relations between A,B,C objects any other way, it makes perfect sense to define the FKs like you did.
Yes, that makes perfect sense. It is not at all uncommon to have a table with multiple foreign keys to other tables.
I think it's ok to do it this way, but maybe that's because I do it this way. In my case, I have a table full of people, and a table full of roles those people can fulfill. Since each person can be in any number of those roles, the simplest way to have it work was to add a third table tracking these relationships.
It's not a great solution, but it's better than adding a new column to the table each time a new role comes along, and having to rewrite the code running those queries each time. And I sure can't think of a better way to handle it!