File: index.md

package info (click to toggle)
sqlmodel 0.0.37-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 16,344 kB
  • sloc: python: 16,107; javascript: 283; sh: 16; makefile: 7
file content (182 lines) | stat: -rw-r--r-- 5,753 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# Many to Many - Intro

We saw how to work with <abbr title="Also called Many-to-One">One-to-Many</abbr> relationships in the data.

But how do you handle **Many-to-Many** relationships?

Let's explore them. 🚀

## Starting from One-to-Many

Let's start with the familiar and simpler option of **One-to-Many**.

We have one table with teams and one with heroes, and for each **one** team, we can have **many** heroes.

As each team could have multiple heroes, we wouldn't be able to put the Hero IDs in columns for all of them in the `team` table.

But as each hero can belong **only to one** team, we have a **single column** in the heroes table to point to the specific team (to a specific row in the `team` table).

The `team` table looks like this:

<table>
<tr>
<th>id</th><th>name</th><th>headquarters</th>
</tr>
<tr>
<td>1</td><td>Preventers</td><td>Sharp Tower</td>
</tr>
<tr>
<td>2</td><td>Z-Force</td><td>Sister Margaret's Bar</td>
</tr>
</table>

/// tip

Notice that it doesn't have any foreign key to other tables.

///

And the `hero` table looks like this:

<table>
<tr>
<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>
</tr>
<tr>
<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>
</tr>
<tr>
<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1</td>
</tr>
<tr>
<td>3</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>
</tr>
</table>

We have a column in the `hero` table for the `team_id` that points to the ID of a specific team in the `team` table.

This is how we connect each `hero` with a `team`:

<img alt="table relationships" src="/img/databases/relationships.drawio.svg">

Notice that each hero can only have **one** connection. But each team can receive **many** connections. In particular, the team **Preventers** has two heroes.

## Introduce Many-to-Many

But let's say that as **Deadpond** is a great character, they recruit him to the new **Preventers** team, but he's still part of the **Z-Force** team too.

So, now, we need to be able to have a hero that is connected to **many** teams. And then, each team, should still be able to receive **many** heroes. So we need a **Many-to-Many** relationship.

A naive approach that wouldn't work very well is to add more columns to the `hero` table. Imagine we add two extra columns. Now we could connect a single `hero` to 3 teams in total, but not more. So we haven't really solved the problem of supporting **many** teams, only a very limited fixed number of teams.

We can do better! 🤓

## Link Table

We can create another table that would represent the link between the `hero` and `team` tables.

All this table contains is two columns, `hero_id` and `team_id`.

Both columns are **foreign keys** pointing to the ID of a specific row in the `hero` and `team` tables.

As this will represent the **hero-team-link**, let's call the table `heroteamlink`.

It would look like this:

<img alt="many-to-many table relationships" src="/img/tutorial/many-to-many/many-to-many.drawio.svg">

Notice that now the table `hero` **doesn't have a `team_id`** column anymore, it is replaced by this link table.

And the `team` table, just as before, doesn't have any foreign key either.

Specifically, the new link table `heroteamlink` would be:

<table>
<tr>
<th>hero_id</th><th>team_id</th>
</tr>
<tr>
<td>1</td><td>1</td>
</tr>
<tr>
<td>1</td><td>2</td>
</tr>
<tr>
<td>2</td><td>1</td>
</tr>
<tr>
<td>3</td><td>1</td>
</tr>
</table>

/// info

Other names used for this **link table** are:

* association table
* secondary table
* junction table
* intermediate table
* join table
* through table
* relationship table
* connection table

I'm using the term "link table" because it's short, doesn't collide with other terms already used (e.g. "relationship"), it's easy to remember how to write it, etc.

///

## Link Primary Key

Cool, we have a link table with **just two columns**. But remember that SQL databases [require each row to have a **primary key**](../../databases.md#identifications-primary-key){.internal-link target=_blank} that **uniquely identifies** the row in that table?

Now, what is the **primary key** in this table?

How to we identify each unique row?

Should we add another column just to be the **primary key** of this link table? Nope! We don't have to do that. 👌

**Both columns are the primary key** of each row in this table (and each row just has those two columns). ✨

A primary key is a way to **uniquely identify** a particular row in a **single table**. But it doesn't have to be a single column.

A primary key can be a group of the columns in a table, which combined are unique in this table.

Check the table above again, see that **each row has a unique combination** of `hero_id` and `team_id`?

We cannot have duplicated primary keys, which means that we cannot have duplicated links between `hero` and `team`, exactly what we want!

For example, the database will now prevent an error like this, with a duplicated row:

<table>
<tr>
<th>hero_id</th><th>team_id</th>
</tr>
<tr>
<td>1</td><td>1</td>
</tr>
<tr>
<td>1</td><td>2</td>
</tr>
<tr>
<td>2</td><td>1</td>
</tr>
<tr>
<td>3</td><td>1</td>
</tr>
<tr>
<td>3 🚨</td><td>1 🚨</td>
</tr>
</table>

It wouldn't make sense to have a hero be part of the **same team twice**, right?

Now, just by using the two columns as the primary keys of this table, SQL will take care of **preventing us from duplicating** a link between `hero` and `team`. ✅

## Recap

An intro with a recap! That's weird... but anyway. 🤷

Now you have the theory about the **many-to-many** relationships, and how to solve them with tables in SQL. 🤓

Now let's check how to write the SQL and the code to work with them. 🚀