Multiple tables need to have one-many relationship with common table - sql

Suppose, I have a SQL database with table like A,B,C and Z. all three table A,B and C has a one-many relationship with table Z. I think of solution mentioned below but need suggestion or better solution for this problem if any.
Solution-
Create one more table named 'LinkZ' which have one-many relationship with table 'Z'
Add foreign key field to table A,B and C of table 'LinkZ'
So that way in future if more tables add to database which need relationship with table 'Z' we just need to add foreign key to newly added table of 'LinkZ' as it has already one-many relationship.
Please suggest solution if exist which satisfy my needs.
Edit -
#Gordon, "If all the tables have a "1-many" relationship with Z, then you don't need a link table at all. You need a link table when your relationships are many-to-many". I need this kind relationship which you have quoted from your answer. but if follow traditional way then i need to add AID, BID, CID in Z to achieve 1-Many with Z then 'Z' table contains many columns which represent foreign key with other table (In future might be other table also included to have same relationship, so in that case i want to avoid many columns from Z of only foreign keys only) that's why I have created dummy table 'LinkZ' which provide illusion to other table A,B and C that this all tables have 1-Many relationship with Z directly.

This is too long for a comment.
If all the tables have a "1-many" relationship with Z, then you don't need a link table at all. You need a link table when your relationships are many-to-many.
It is unclear which way the linkage is going, but you either want ZID in each of A, B, and C, or you want AID, BID, CID in Z.

Related

A field referencing two tables - Foreign Key Conflict

Please check the tables below for a simplified version of my problem:
Table Boys
BoyId
BoyName
...
Table Girls
GirlId
GirlName
Table Toys
ToyId
ToyName
ToyOwnerBoyOrGirl ( The toy could be owned by a boy or a girl)
ToyOwnerId
I created two constraints:
1) ToyOwnerId is a foreign key of the Primary Key Boys.BoyId
2) ToyOwnerId is a foreign key of the Primary Key Girls.GirlId
My purpose is to tell the database that ToyOwnerId will always be one of these Ids
My problem:
When I tried to insert a new Toy with an id of a Boy, I got an error that there is a foreign key conflict in the Girls constraint.
Is this a bag design or I can still use the same design with a fix ?
I think you should combine the boys and girls table to one table called children. It would have sex column that would have an M or F. That will simplify things.
You should simply have both IDs in your toys table plus a check constraint to ensure that always either a boy or a girl is the owner.
Table Toys
ToyId
ToyName
ToyOwnerBoyId
ToyOwnerGirlId
CONSTRAINT chkToyOwner CHECK
(
(ToyOwnerBoyId is null and ToyOwnerGirlId is not null)
OR
(ToyOwnerBoyId is not null and ToyOwnerGirlId is null)
)
As to selecting the data, use outer joins:
select ...
from toys
left join boys on boys.boyid = toys.toyownerboyid
left join girls on girls.girlid = toys.toyownergirlid;
To find toys owned by boys:
select ...
from toys
where toyownerboyid is not null;
It looks like a bad design. Why don't have one table for all children and some mark - is it boy or girl? Also I really doubt you need ToyOwnerBoyOrGirl field - as it can be easily obtained by join from toys to owners.
Consider following scheme:
Table Children
ID
Name
Is_Boy
Table Toys
ID
Name
Owner_ID
In this case you need just foreign key from toys to owners, and other tasks you might encounter will be much more simplier to solve.
EDIT: As per OP's comment - Boys and Girls tables are totally different.
So, in this case you still can have table Children (let's use previous terminology) as a "common" table for Boys and Girls.
Something like:
Table Children
ID
Table_Name ('Boys' or 'Girls' here)
Record_ID (ID from Boys or Girls respectively)
...maybe some common fields from boys and girls tables here...
Table Boys
ID
Child_ID
...the rest of fields
Table Girls
ID
Child_ID
...the rest of fields
It's a bad design, given the fact one column set (one column, being ToyOwnerId) is referred to different tables, both as a one-column FK to a one-column PK. The obvious question would then be : how come you have different tables with a similar PK ? And I see you have answered that already, by means of replying the data columns of the respective tables are different. That is a good reason to have different tables. But, then, how to solve the FK issue ? (I understood that these "boys" and "girls" are not the real entities). What you can do, is make a BoyToy and a GirlToy table. If you have very few data columns (data = non-PK and non-FK) then that is a perfect solution. No ?

Is OneToOne the right association for one-to-less-than-one in Doctrine?

If I am relating two tables where each record in each table will not relate to more than one record in the other table, I assume that OneToOne is the right Doctrine association to use. However, if the table that s not the owning side does not have a record for every record in the owning side table, is that really one-to-one?
For example, Table A may have 100 records and Table B may have 20 records. The 20 records in Table B have a one-to-one relationship with 20 of the records in Table A, but another 80 records in Table A do not have a relationship with any records in Table B at all.
The correct answer to your question will be sticking with One-to-One relationship. It doesn't matter all records in Table A are not relating with Table B. As long as you are sure that 1 record in Table B does not refer to more than 1 row in Table A, you can stick with 1-to-1. When it comes to mapping in Doctrine, in the Table B side use the 'mappedBy' attribute. And you may not necessarily include the 'inversedBy' attribute in Table A, as not all records in Table A relates with Table B.
Hope this helps.
Cheers!

How to stablish a one to many relationship between 2 tables

I'm dealing with this situation. I've got three tables in SQL SERVER called Movies, Series and Orders.
Orders has an ItemId where this could be a MovieId (Movies PK) or SerieId (Series PK). I mean, in Orders table could have records where are from movies of series.
I don't know how to maintain this relationship or which could be the best way to implement it. Until I know, I only can create 1 to 1 or 1 to many relationships between 2 tables, not for 3.
Thanks in advance.
In this case I think it would be better to store Movies and Series in the same table with the common attributes incl. a column which indicates the type (Movie or Serie) and then have the additional attributes in seperate tables (if you want to normalize) or even in the same table (in order to avoid joins).
You should learn about implement table inheritance in sql-server.
Do you have a product and this product may be a Movie or a Serie.
In linked sample a person may be a student or a teacher.
The best way is:
create a generic table for movies and series with the fields that both entities should share (like ItemId).
create a table for movies that references the table created on step 1, containing the fields that must be compiled only for movies. This new table will be in relation one-to-one with the previous one.
same thing for series.
create the orders table and set ItemId foreign key to point to the ItemId primary key of the table created on step 1.

separate columns for separate id fields?

Say we have tables A, B, and C and then we want table Z to contain column TYPE which tells us which table of A, B, and C the record in Z is associated with.
Is it better to have a separate column for each table like columns A_ID, B_ID, and C_ID in order to use indexing?
Or is there some reason why using a generic column TYPE_ID might be better performance-wise?
Using a type_id and then a fk_id won't be good because selectivity on the index is 33%, which is too high to be of any use. You would always be indexing on the fk_id instead (that which links to A,B,C) - which may require tie breaking between 3 values (if the id is used by all 3 types).
Storage wise, an index never stores nulls, so the absolute number of items stored in the indexes, whether a single (fk_id) or multiple (a_id,b_id,c_id) will be similar.
If you are coming in from the exact fk_id (from either A,B,C), then using a unique index on (fk_id,type_id) in that order can quickly identify the record required.
It would seem for simplicity and brevity, two columns are better than 3 here.
This is sometimes a schema code smell.
If you are considering putting this as a single column in Z, does that mean that only one of A, B, C can be applicable to Z?
Before I decide, I'd really say I have to know more about the entity and the usage pattern. Is access coming from known A, B, or C, or is the supplemental info driven from the Z side? If it is driven from the Z side, do you want to get all the A, B and C columns and then use them selectively from the application, or just Zs with As or Zs with Bs - i.e. do you usually know the subtype? Also, do A, B, and C have enough columns to merit the separation out of Zs row if they are each 1-1 (i.e. you could have the columns in Z and just be NULL)
Just for completeness, another possibility which gives you more referential integrity (because with a single column, you can't be an FK to one of three tables) is to have tables Z_A, Z_B, Z_C:
With schemas:
Z_A:
Z_ID REFERENCES (Z.ID)
A_ID REFERENCES (A.ID)
Z_B:
Z_ID REFERENCES (Z.ID)
B_ID REFERENCES (B.ID)
Z_C:
Z_ID REFERENCES (Z.ID)
C_ID REFERENCES (C.ID)
With all IDs unique in each table, this constrains everything pretty nicely, except there is nothing declarative to stop Z lying in multiple tables without a trigger (you cannot make a unique constraint on an indexed view over a UNION ALL in SQL Server).
While it seems to multiply the number of tables, these can usually be wrapped up into views.

Reversing a 1:many relationship between two tables

I have two MySQL tables A and B. Table A has a member ref which is a ForeignKey reference to B.id. This makes for a 1:many association between B and A.
This has been in production for a few weeks, but I'm now adding more features to my code and have realized I got my original mapping wrong. I needed a many:1 relationship between B and A. That is, B.ref should point to A.id, not the other way around. It wasn't a problem until now because it was all 1:1 mapping so far. How do I migrate my data to the new schema?
I'd guess:
ALTER TABLE B ADD COLUMN ref INTEGER CONSTRAINT FOREIGN KEY (A.id) -- add the column first
Run the SQL equivalent of "for row in A: row.ref.ref = row"
ALTER TABLE A DROP COLUMN ref
Attempting to do this in SQLAlchemy fails with a circular reference error. I need to do it in SQL, but am not familiar with the necessary SELECT+UPDATE syntax. Help?
For step 2:
update b, a
set b.ref = a.id
where a.ref = b.id
Just add the foreign key constraint as fourth step, you won't need it when creating the column.