Skip to content
wannacode

Relationship types: 1:1, 1:N, M:N

In short: A relationship between two tables is one-to-one, one-to-many or many-to-many, and its type decides where the foreign key goes and when you need a junction table.

Problem

A card and tags

The shop is launching two new things. The first is a loyalty card: every customer can have one card with points. The second is product tags, such as “vegan”, “gluten-free” and “organic”, so the website can filter by them.

Where do you store them? A column card_number in customers? A column tags in products with the text “vegan, organic”? The answer depends on one question: how many things on one side match how many on the other.

The idea

One to many (1:N)

One customer has many orders. Each order belongs to one customer. This is a one-to-many relationship, written 1:N.

The key goes on the “many” side. Each order says whose it is with customer_id:

customers

  • PKidinteger
  • nametext *
  • emailtext *
  • citytext
  • joined_attext *

orders

  • PKidinteger
  • FKcustomer_idinteger *→ customers
  • ordered_attext *
  • statustext *

The other way round does not work. How many columns order_1, order_2 should a customer have? Maria has 12 orders, and tomorrow she will have 13.

SQLdatabase: shop

This is the most common relationship. In the shop, a category and its products are like this too, and so are a product and its reviews.

Try it

Products by category

How many products are in each category that has products? Show the category name and the count.

SQLdatabase: shop

The idea

One to one (1:1)

Every customer has at most one card, and every card belongs to one customer. This is one-to-one, 1:1. You store it like 1:N, with a key to the customer, plus one more rule: UNIQUE.

loyalty_cards

  • PKidinteger
  • FKcustomer_idinteger *→ customers
  • numbertext *
  • pointsinteger *
  • issued_attext *
SQLdatabase: shop

Five customers have a card. Try giving Maria a second one:

SQLdatabase: shop

UNIQUE on customer_id does not let in a second row for the same customer. Without it, the relationship would be 1:N.

Why not columns in customers? That works too. Often 1:1 is just more columns in the same table. A separate table makes sense when most rows do not have the second part (15 of the 20 customers have no card and would have empty cells), or when it has a life of its own: the card gets lost, replaced, it has its own points.

Try it

Who has no card yet

Marketing wants to offer a card to every customer who does not have one yet. Show their names.

SQLdatabase: shop

The idea

Many to many (M:N)

One order has many products. One product is in many orders. This is many-to-many, M:N.

Here the key cannot go in either of the two tables. The answer is a third table, a link table, with one row for each pair. In the shop this is order_items: each row is one product in one order, with the quantity and the price.

products

  • PKidinteger
  • nametext *
  • FKcategory_idinteger→ categories
  • pricereal *
  • stockinteger *
  • added_attext *

order_items

  • PKorder_idinteger→ orders
  • PKproduct_idinteger→ products
  • quantityinteger *
  • unit_pricereal *

Which orders have the coffee (product 17)?

SQLdatabase: shop

Tags are the same. A product has many tags, and a tag is on many products:

tags

  • PKidinteger
  • nametext *

product_tags

  • PKproduct_idinteger→ products
  • PKtag_idinteger→ tags
SQLdatabase: shop

See it

The pair is the key

The primary key of order_items is the pair (order_id, product_id). Try adding the bread a second time to order 60, which already has it:

SQLdatabase: shop

The database does not allow the same pair twice. A product is in the order once, and more pieces go into quantity. Otherwise the report “how many times was the bread ordered” would count the same product from one order twice.

1. Every product has exactly one category, and a category has many products. Where does the key go?

Try it

Tags on the website

Next to each tag, the website shows how many products have it. Show the tag name and the count.

SQLdatabase: shop

Exercise

Two tasks

1. The apples page shows their tags. Which are they?

The tags of the product “Apples”:

SQLdatabase: shop

2. A customer is looking for products that are both vegan and gluten-free. Show their names.

The products with both tags, “vegan” and “gluten-free”:

SQLdatabase: shop

Test

Check yourself

1. What makes the relationship between loyalty_cards and customers 1:1 rather than 1:N?
2. A student takes many courses, and a course has many students. How do you store that?
3. Why is the primary key of product_tags (product_id, tag_id)?
4. Why does the query with WHERE t.name = 'vegan' AND t.name = 'gluten-free' find nothing?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·