Created
February 22, 2019 20:35
-
-
Save neall/bcefa3e6484f5cbca1d56dee66c3643f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- <- double dash is the SQL way to say "the rest of this line is a comment" | |
-- Join tables are how you do many-to-many relationships | |
-- in relational databases, and they're just complicated | |
-- enough that it puts some people off. But once you get | |
-- used to them, I don't think they're too bad. | |
-- ** Creating Our Tables ** | |
CREATE TABLE articles ( | |
id BIGSERIAL PRIMARY KEY, | |
title VARCHAR NOT NULL, | |
body VARCHAR NOT NULL | |
); | |
-- Defining a field as bigserial is shorthand for making it | |
-- use bigint and creating an auto-incrementing sequence it | |
-- will default to. | |
-- Also when you declare a field as a primary key, that | |
-- automatically makes it both UNIQUE and NOT NULL. | |
-- | |
-- You can limit your varchar fields by saying something like | |
-- varchar(32) if you're *sure* you'll never need more than 32 | |
-- characters, but Postgres handles unconstrained varchar | |
-- columns pretty efficiently. And there are other string | |
-- types, but you mostly just want to use varchar nowadays. | |
-- Also, NOT NULL fields can still be empty string, so watch | |
-- out for that. | |
CREATE TABLE tags ( | |
id BIGSERIAL PRIMARY KEY, | |
tagname VARCHAR UNIQUE NOT NULL | |
); | |
CREATE TABLE article_tags ( | |
article_id BIGINT NOT NULL REFERENCES articles(id), | |
tag_id BIGINT NOT NULL REFERENCES tags(id), | |
PRIMARY KEY (article_id, tag_id) | |
); | |
-- REFERENCES creates a foreign key relationship. This prevents | |
-- you from inserting `article_id`s that don't exist in the `id` | |
-- field of `articles` or `tag_id`s that aren't in the `tags(id)` | |
-- column. | |
-- | |
-- In the first two tables, we specified our single-column | |
-- primary key in-line, but if you want a composite primary | |
-- key, you specify it like this. | |
-- ** Inserting Our Data ** | |
INSERT INTO articles (title, body) | |
VALUES ( | |
"Ten Amazing Query Facts You Won't Believe!", | |
"1. Did you know that SQL..." | |
) | |
RETURNING id; | |
-- The `RETURNING` clause on `INSERT` doesn't exist in every | |
-- db engine - some databases make you make a second query to | |
-- figure out what your auto-generated `id` was. | |
-- | |
-- We'll say that this query returns [{id: 1}] | |
INSERT INTO tags (tagname) | |
VALUES | |
("clickbait"), | |
("database") | |
RETURING id; | |
-- Since we inserted two rows here, this query will | |
-- return [{id: 1}, {id: 2}] | |
INSERT INTO article_tags (article_id, tag_id) | |
VALUES | |
(1, 1), | |
(1, 2) | |
-- associate both our tags with our article | |
-- ** querying our data ** | |
SELECT | |
articles.id, | |
title, | |
body | |
FROM | |
articles | |
INNER JOIN article_tags ON articles.id = article_id | |
INNER JOIN tags ON tags.id = tag_id | |
WHERE tagname = "database"; | |
-- when you join tables, you can filter on and/or select | |
-- fields from each table. If the column name would be | |
-- ambiguous (articles and tags both have id columns) you | |
-- have to specify in the full "tablename.columnname" format. | |
-- | |
-- This will return [{id: 1, title: "Ten amaz...", body: "1. Did you..."}] | |
-- (ignore that I didn't want to write out the whole strings again). | |
-- Important thing about inner joins: they give you back all the | |
-- matches on each side. Above we filtered back down to just one result | |
-- with our `WHERE` clause. But compare to this example with no `WHERE` clause: | |
SELECT | |
articles.id AS aid, | |
title, | |
body, | |
tags.id AS tid, | |
tagname | |
FROM | |
articles | |
INNER JOIN article_tags ON aid = article_id | |
INNER JOIN tags ON tid = tag_id | |
-- This will return | |
-- [ | |
-- {aid: 1, title: "Ten amaz...", body: "1. Did you...", tid: 1, tagname: "clickbait"}, | |
-- {aid: 1, title: "Ten amaz...", body: "1. Did you...", tid: 2, tagname: "database"} | |
-- ] | |
-- Also note that I gave `articles.id` and `tags.id` aliases using | |
-- the `AS` keyword. This is useful in my result and also so I | |
-- don't have to keep writing the long form later in the query. | |
-- You can use `AS` to make aliases for table names as well, which | |
-- can save you some typing but is also practically required if | |
-- you need to join against the same table more than once. | |
-- There are a *lot* more things you can do with `SELECT`s - I've | |
-- basically just shown a minimal many-to-many relationship here. | |
-- Postgres has excellent docs. If you're looking for full | |
-- references for specific commands, look at: | |
-- https://www.postgresql.org/docs/current/sql-commands.html | |
-- but for a more topic-relevant browsable docs look at: | |
-- https://www.postgresql.org/docs/current/sql.html |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment