heisenberg
heisenberg

Reputation: 1954

Foreign Key or Composite Key?

I just started applying everything that I read about table relationships but I'm kind of confused on how to insert data on tables with MANY-TO-MANY relationship considering there's a third table.

Right now I have these tables.

subject

name
code PK
units
description

schoolyear

schoolyearId PK
yearStart
yearEnd

schoolyearsubjects (MANY TO MANY table)

id PK
code FK
schoolyearId FK

But the problem with the above schoolyearsubjects table is that, I don't know how I can insert the schoolyearId from the GUI. On the GUI screenshot, as soon as "Save" button is clicked, a TRANSACTION containing 2 INSERT statements (to insert on subject) and (to insert on schoolyearsubjects) will execute. If I stick with the above, I'll have to insert the schoolyearId. schoolyearId definitely won't come from GUI.

enter image description here

I'm thinking of changing the columns of schoolyearsubjects and schoolyear to this:

schoolyear

--composite keys (yearStart, yearEnd)
yearStart (PK)
yearEnd (PK)

schoolyearsubjects(MANY TO MANY table)

id PK
code (FK)
yearStart (FK) --is this possible?
yearEnd (FK) --is this possible?

1.) Is the solution to change the columns and make a composite key so I can just insert yearStart and yearEnd values instead of schoolyearId?

2.) Is my junction / linking table schoolyearsubjects correct?

3.) What can you advise?

I'd appreciate any help.

Thanks.

Upvotes: 2

Views: 124

Answers (3)

Loa
Loa

Reputation: 2240

For me schoolyear is a period, and as such, there is no need to use a surrogate key here. This always makes things more confusing, and it is always more difficult to develop a graphical interface for it (I'm talking about how we model periods as developers).

If you stop to think, periods are seen itself as something unique. Will you have a period equal to the other? Stop and think. Even if you have, this will occur in years or different times. So we already have a primary key for schoolyear. Eliminate "schoolyard PK" from schoolyear. Use composite key here with yearStart and yearend. So, your schoolyear entity (in future, table) will be like:

  • yearStart PK
  • yearEnd PK

In the intermediate table, you will have 3 fields as composite primary key (also foreign key!):

  • yearStart PK FK (from schoolyear)
  • yearEnd PK FK (from schoolyear)
  • code PK FK (from subject)

This will permit that a period have only a single subject. If, on the other hand, you want a period with more than one subject, you would have to put a surrogate key here.

Now, to draw the graphical interface, you will only have to use a select box (combo box). In this case you will have each item as a text, something like "from year X to Y" (a period). Your users can very well understand and select it.

Note: In anyway, you may not have the ID of a record in an interface, but the values that identify it. This is permissible to be seen, and identifies a record of their remaining.

If, however, you do not have periods as something unique, then "yearStart" and "yearEnd" are fields in subject entity, and there is no schoolyear entity. To be honest, the entity "schoolyear" should only exist if you want to reuse it's records to relationships with other records of other(s) table(s). I'm not saying this is or is not the case. Watch out as well. If you do this you say that every period has only one subject (as fields). I do not know if this is exactly what you want. We must always remember the most important thing in shaping an ER-Diagram:

  • CONTEXT

Check your context. What does it ask? If you have any questions, please comment. If you can offer me some more context here, I can help you more.

Upvotes: 1

Andriy Simonov
Andriy Simonov

Reputation: 1288

With your current scheme you can insert the schoolyearId with a request as follows:


    INSERT INTO schoolyearsubjects (id, code, schoolyearId)
    VALUES ( ${id},
             ${code_from_GUI},
             ( SELECT schoolyearId
               FROM schoolyear
               WHERE yearStart=${start_from_GUI} AND yearEnd=${end_from_GUI})
           );

For this to work, the unique constraint on (yearStart, yearEnd) in the schoolyear table is required.

As to the rest of your questions:
1) You can use a composite key in the schoolyear table it will work either way.
2) The schoolyearsubjects is correct as it allows to write join queries. If you get rid of the schoolyearId columns than you will not probably need the schoolyear table alltogether as all data you may want to get will be in the schoolyearsubjects table.
3) This article may help to deside what type of key to use.

Upvotes: 0

onedaywhen
onedaywhen

Reputation: 57023

Assuming you have parameters @code, @yearStart and @yearEnd with values from the UI:

INSERT INTO schoolyearsubjects ( code, yearStart, yearEnd )
SELECT @code, y.yearStart, y.yearEnd
  FROM schoolyear y
 WHERE @yearStart <= y.yearStart
       AND y.yearEnd <= @yearEnd;

...but I think you have a design flaw with your schoolyearsubjects because it allows duplicates e.g. doing this:

INSERT INTO schoolyearsubjects VALUES ( 'code red', '2016', '2017' );
INSERT INTO schoolyearsubjects VALUES ( 'code red', '2016', '2017' );
INSERT INTO schoolyearsubjects VALUES ( 'code red', '2016', '2017' );

looks like it would result in three de facto duplicate rows.

Upvotes: 0

Related Questions