Many-to-many relationship

Both sides can have several of the other, so a middle table stores each link, like memberships between users and teams.

users can join many teams and teams have many userstable between two tableshow do I store posts with multiple tagsmany to manny relationshipjunction tablejoin table with two idshow do I let one user belong to several projectsmemberships table between users and groups

See it

Live demo coming soon

What it is

A many-to-many relationship means rows on both sides can relate to several rows on the other: users join many teams and a team has many users. Relational databases represent it with a junction table such as memberships, with one foreign key to users and one to teams. Each row in the junction is one connection.

Reach for it when the connection is a real set rather than one side owning the other. The junction can carry facts about that connection, such as a member's role, joined_at date, or notification setting. At that point it is often useful to think of Membership as its own model, not invisible plumbing. Frameworks encode the same lesson: Rails teams reach for has_many :through over the older has_and_belongs_to_many precisely because the first one gives the link a real model, and Django's ManyToManyField hides its through table until you need to add a column and have to declare it anyway.

Gotcha: two foreign keys do not stop the same pair being inserted twice. Make (user_id, team_id) the composite primary key, or add a unique constraint on that pair if the table has a separate id. Indexing the reverse order can also matter: the pair starting with user_id finds a user's teams, but a second index starting with team_id helps find a team's users.

Ask AI for it

Model this PostgreSQL many-to-many relationship with an explicit junction table. Add NOT NULL foreign keys to both parent tables, make the pair a composite PRIMARY KEY, and add relationship attributes such as role or created_at only when they belong to the link itself. Choose each ON DELETE action explicitly, create a reverse-order B-tree index when both lookup directions are used, and do not store arrays of ids on either parent. Output the CREATE TABLE and CREATE INDEX statements plus queries for both directions and a test proving the same pair cannot be inserted twice.

You might have meant

one to many relationshipforeign keyjoinunique constraintnormalization