Jed Rembold
February 12, 2025

You will almost always start from an initial basic image
A collection of universally accessible images is hosted on DockerHub
These are all images in themselves, but also serve as excellent starting points for more custom images that you might want to build
To download an image to your system for use, from a terminal:
docker pull image_name:possible_tagTo see images currently on your system:
docker imagesTo actually run a container, you can use the GUI, or, from a terminal:
docker run --flags container_name
run creates and starts the container--flags could be any number of options or
boolean flags. Common ones include:
-it to launch interactively--rm to remove the container once the
command or interactive session finishes-d to run the container detachedTo get a view of currently running containers:
docker ps
-a flag at the end to see
all containersTo remove old containers:
docker container rm container_name_or_idCan start or stop exist containers with:
docker start/stop container_nameGenerally, you will want to customize a base image by adding your own layers on top
The schematic of what comprises an image is all contained in a
special text file, named Dockerfile
A Dockerfile is a simple text file with some special instructions that dictate what layers comprise your image
A Dockerfile is used to build the image
docker build -t img_name path/to/dockerfileFROM specifies the base image you are
starting withRUN specifies a command to run. Often to
satisfy dependencies or get librariesCOPY will copy file from your local
system into the imageCMD specifies the default command to be
run when the image is launchedFROM python:3
WORKDIR /app
COPY image.py .
RUN pip install numpy matplotlib
CMD ["python", "image.py"]
Connecting ports
docker run -p localport:containerport cont_nameConnecting folders
docker run -v /local/folder:/container/folder cont_namejrembold/dockerdemo
Given the table (named employees) to the
right and the query immediately below, what would the output table look
like?
SELECT p1.name, p2.name
FROM employees as p1
LEFT JOIN employees as p2
ON p1.superior id > p2.id
ORDER BY p1.name LIMIT 2;
| id | name | superior_id |
|---|---|---|
| 1 | Bob | NULL |
| 2 | Frank | 1 |
| 3 | Kelly | 1 |
| 4 | Anne | 3 |
| 5 | Tiffany | 2 |
| 6 | Henry | 4 |
| name | name |
|---|---|
| Anne | Kelly |
| Bob | NULL |
| name | name |
|---|---|
| Anne | Kelly |
| Frank | Bob |
| name | name |
|---|---|
| Frank | Bob |
| Kelly | Bob |
| name | name |
|---|---|
| Anne | Bob |
| Anne | Frank |
YYYY-MM-DD to
the table name to make it easier to find later what your latest version
is.Postgres gives you two main locations where you can apply constraints:
For the most part, all the different types of contraints can be applied in either location
The anatomy of a constraint syntax looks like:
CONSTRAINT |||constraint name||| |||CONSTRAINT_TYPE||| |||CONSTRAINT_CONDITIONS|||CHECK constraint is perhaps the most
straightforward, in that it just checks to see if a certain condition is
trueCREATE TABLE |||tablename||| (
|||col₁||| INT CHECK (|||col₁||| > 0),
|||col₂||| INT,
|||col₃||| INT,
CONSTRAINT |||constraint_name||| CHECK (|||col₂||| > |||col₃|||)
);
NOT NULL constraint is only applied
to columns, not to the entire table!CREATE TABLE |||tablename||| (
|||col₁||| INT NOT NULL,
|||col₂||| INT
);
CREATE TABLE |||tablename||| (
|||col₁||| INT UNIQUE,
|||col₂||| INT,
|||col₃||| INT,
CONSTRAINT |||constraint_name||| UNIQUE (|||col₂|||, |||col₃|||)
);
Given the table created as seen below, which insertion command would complete successfully?
CREATE TABLE uc (
id_num INT UNIQUE NOT NULL,
prod_name TEXT UNIQUE,
price NUMERIC(5,2)
wholesale NUMERIC(5,2),
CHECK (price > wholesale),
CHECK (price >= 0)
);
INSERT INTO uc VALUES
(1, 'Steak', 3.22, 5.00),
(2, 'Beans', 4.12, 2.50));
INSERT INTO uc VALUES
(1, 'Steak', 3.22, 1.23),
(2, NULL, 2.65, 1.26));
INSERT INTO uc VALUES
(1, 'Steak', 3.22, 2.78),
(NULL, 'Beans', 4.12, 2.50));
INSERT INTO uc VALUES
(1, 'Steak', -3.22, -5.00),
(2, 'Steak', 4.12, 2.50));
UNIQUE and
NOT NULL is so common that such a constraint
gets its own name: the primary keySERIAL data types are great for this,
or some people prefer to use UUIDsCREATE TABLE |||tablename||| (
|||col₁||| TEXT PRIMARY KEY,
|||col₂||| INT
);
CREATE TABLE |||tablename||| (
|||col₁||| TEXT,
|||col₂||| INT,
|||col₃||| INT,
CONSTRAINT |||constraint_name||| PRIMARY KEY (|||col₁|||, |||col₂|||)
);
Tables can be related to other tables: foreign key constraints are a way to formalize these relationships
Says: “the values in this column are related to this other column in this other table”
Could have many foreign key constraints in one table, as opposed to having only a single primary key constraint
Uses the keyword REFERENCES
CREATE TABLE |||table₂||| (
|||col₁||| TEXT PRIMARY KEY,
|||col₂||| INT REFERENCES |||table₁||| (|||col₁|||)
);CREATE TABLE |||table₂||| (
|||col₁||| TEXT PRIMARY KEY,
|||col₂||| INT,
|||col₃||| INT,
CONSTRAINT |||constraint_name||| FOREIGN KEY (|||col₂|||, |||col₃|||)
REFERENCES |||table₁||| (|||col₁|||, |||col₂|||)
);
NULL or the column default...
|||col₂||| INT REFERENCES |||table₁||| ON DELETE CASCADE
|||col₃||| INT REFERENCES |||table₁||| ON DELETE SET NULL
...
Suppose you wanted to track your Spotify playlist information in your own database. Questions you may want to be able to answer might include:
In groups of two or three, sketch out table diagrams similar to what we just saw in the previous example (commonly called ERD or Entity Relationship Diagrams), that would allow all these questions to be answered. Your tables should include primary keys and foreign keys where appropriate.
Online sketching resources include: drawsql, visual-paradigm, or DrawIO
UNIQUE constraintCREATE INDEX |||index_name||| ON |||table||| (|||column|||);
EXPLAIN keyword to give
you information about what the database is doing in the backgroundEXPLAIN ANALYZE will also give you
timing information about how long it took a query to runEXPLAIN always comes at the start of your
query