-d dpage/pgadmin4
```
* 
---
* Both PostgreSQL and pgAdmin are now running in our *local* Docker. To connect pgAdmin to PostgreSQL, we need the IP address used inside Docker.
* Using Docker's inspect, we'll get Docker's internal IP for `my-postgres -container`. Since the command produces quite a lot of information, we pipe the result to `grep` (Linux) or `findstr` (Windows) to see only the rows that contain the word `IPAddress`
#### Linux
```bash
docker inspect | grep IPAddress
```
#### Windows
```powershell
docker inspect | findstr IPAddress
```
* In the example output, the IP Address is `172.17.0.2`:

### Logging into pgAdmin
#### With Docker:
1) With pgAdmin running, navigate your web browser to http://localhost:5050
#### Without Docker:
1) Run pgAdmin from the Start menu.
2) Use the username and password you provided to log in.

### Connecting PgAdmin to our DB
1) Now we have all that we need for a connection. In pgAdmin, select
*Object > Register > Server*.
* If the *Object* menu is greyed out, click on *Servers*.

2) In the *General* tab, give the server a name that identifies the connection.

---
3) In the *Connection* tab, enter:
1) *Host name/address*
* the internal Docker address
2) *Port*, *Username*, and *Password*
* the values defined when running the PostgreSQL container
4) Then click *Save*. You should see all the databases available on this server.


### Exercise 2: pgAdmin basics
1) If using Docker, start a local instance of pgAdmin in Docker
2) Following lecture instructions, connect the pgAdmin to your already running PostgreSQL server.
3) Verify that you can see the database created in the previous assignment.
## Using PostgreSQL
### Creating a database
With pgAdmin:
1) Right-click *Servers > my-postgres > Databases*
2) Select _Create > Database..._
3) Insert a name for the database and hit _Save_
With psql:
1) Enter command (*remember `;`!!!*)
```sql
CREATE DATABASE ;
```
2) After creating a new database, you still need to connect to it with `\c`

### Querying
With pgAdmin:
1) Right-click _sqlpractice > Query tool..._
2) Insert a query into the _Query Editor_ and hit _Execute_ (F5)


---
With psql:
1) List all available databases with `\l`
2) Connect to the created database with `\c `
3) List all tables in the database with `\dt`
4) Type a query and press enter
* Here's an [example query](code-examples/example-query.sql)
### Editing data with pgAdmin
* Tables of data in a database are found under *Database > Schemas > Tables*
* Inspect and edit data in pgAdmin by right-clicking a table and selecting _View/Edit Data_

---
* Individual values in the table can be directly modified by double clicking the value and then editing the value in the visual user interface
* Save the changes by pressing the _Save Data Changes_ button


## Exercise 3: Preparing the database
Using either pgAdmin or psql,
1) Insert the provided [example query](code-examples/example-query.sql) to the new database
2) Verify that the query has created new tables to your database
## Basic SQL queries
* `SELECT`
* `INSERT`
* `DELETE`
* `UPDATE`
* `CREATE` & `DROP`
### Querying data with `SELECT`
* Syntax:
```sql
SELECT column1, column2, column3 FROM table_name;
```
* Examples:
```sql
SELECT full_name, email FROM users;
SELECT full_name AS name, email FROM users;
SELECT * FROM users;
```
### Filtering data with `WHERE`
* Syntax:
```sql
SELECT column1, column2 FROM table_name WHERE condition;
```
* Text is captured in **_single quotes_**.
* In a `LIKE` condition, `%` sign acts as a wildcard.
* `IS` and `IS NOT` are also valid operators.
* Example:
```sql
SELECT full_name FROM users
WHERE full_name = 'Teppo Testaaja';
SELECT * FROM books WHERE name LIKE '%rr%';
SELECT * FROM books WHERE author IS NOT null;
```
### Ordering data with `ORDER BY`
* Syntax:
```sql
SELECT column1 FROM table_name ORDER BY column1 ASC;
```
* Examples:
```sql
SELECT full_name FROM users
ORDER BY full_name ASC;
SELECT full_name FROM users
ORDER BY full_name DESC;
```
### Combining data with `JOIN`
* Also known as `INNER JOIN`
* Corresponds to ***intersection*** from [set theory](https://en.wikipedia.org/wiki/Set_theory)

### JOIN examples
```sql
SELECT
users.id, users.full_name, borrows.id,
borrows.user_id, borrows.due_date, borrows.returned_at
FROM users
JOIN borrows ON
users.id = borrows.user_id;
```
```sql
SELECT
U.full_name AS name,
B.due_date AS due_date,
B.returned_at AS returned_at
FROM users AS U
JOIN borrows AS B ON
U.id = B.user_id;
```
### Combining with `LEFT JOIN`
* Also known as `LEFT OUTER JOIN`
* Example:
```sql
SELECT
U.full_name AS name,
B.due_date AS due_date,
B.returned_at AS returned_at
FROM users AS U
LEFT JOIN borrows AS B ON
U.id = B.user_id;
```

### Exercise 4: Querying the library
Using SQL queries, get
1) all columns of loans that are borrowed before `2020-10-27`
2) all columns of loans that are returned
3) columns `user.full_name` and `borrows.borrowed_at` of the user with an `id` of `1`
4) columns `book.name`, `book.release_year` and `language.name` of all books that are released after 1960
### Inserting data with `INSERT`
* Syntax
```sql
INSERT INTO table_name (column1, column2, column3) VALUES (value1, value2, value3);
```
* Example
```sql
INSERT INTO users (full_name, email, created_at)
VALUES ('Pekka Poistuja', 'pekka.poistuja@buutti.com', NOW());
```
* Since `id` is not provided, it will be automatically generated.
### Updating data with `UPDATE`
* Syntax
```sql
UPDATE table_name SET column1 = value1, column2 = value2 WHERE condition;
```
* *__Notice:__* if a condition is not provided, all rows will be updated!
* If updating only one row, it is usually best to use `id`.
* Example
```sql
UPDATE users SET email = 'taija.testaaja@gmail.com' WHERE id = 2;
```
## Removing data with `REMOVE`
* Syntax
```sql
DELETE FROM table_name WHERE condition;
```
* Again, if the _condition_ is not provided, `DELETE` affects _all_ rows
* Before deleting, it is a good practice to execute an equivalent `SELECT` query to make sure that only the proper rows will be affected.
* Example:
```sql
SELECT * FROM users WHERE id = 5;
DELETE FROM users WHERE id = 5;
```
### Exercise 5: Editing data
1) Postpone the due date of a loan with an `id` of `1` by two days in the `borrows` table
2) Add a couple of new books to the `books` table
3) Delete one of the loans.
### Initializing data with `CREATE TABLE`
* Before data can be manipulated, a database and its tables need to be initialized.
* Syntax
```sql
CREATE TABLE table_name (
column1 datatype,
column2 datatype,
...
);
```
* Example:
```sql
CREATE TABLE "users" (
"id" SERIAL PRIMARY KEY,
"full_name" varchar NOT NULL,
"email" varchar UNIQUE NOT NULL,
"created_at" timestamp NOT NULL
);
```
### Removing data with `DROP`
* In order to remove tables or databases, we use a `DROP` statement
```sql
DROP TABLE table_name;
DROP DATABASE database_name;
```
* These statements do not ask for confirmation and there is no undo feature. Take care when using a drop statement.
---
* I'm legally obliged to include this XKCD comic here.

## NoSQL
* In addition to SQL databases, there's ***NoSQL***
* There are many differing definitions, but...
* most agree that NoSQL databases store data in a format other than tables
* They can still store relational data - just _differently_
* Four different database types:
* Document databases
* Key-value databases
* Wide-column stores
* Graph databases
* Example database engines include [MongoDB](https://www.mongodb.com/), [Redis](https://redis.io/) and [Cassandra](https://cassandra.apache.org/_/index.html)
* For more info, see [MongoDB: What is NoSQL?](https://www.mongodb.com/resources/basics/databases/nosql-explained)
## Object-Relational Mappers
* Object-Relational Mappers, or ORMs allow the developer to write code instead of SQL to perform CRUD operations on their database
* An abstraction layer between code and database
* Can make database logic easier to read and write
* Prevents SQL injection by sanitizing input (see the comic before...)
* ...but sometimes you'd rather just write the SQL queries themselves
* Some popular ORMs:
* Hibernate (Java)
* EFCore (.NET)
* Sequelize (Node.js)
* TypeORM (TypeScript) ([documentation](https://typeorm.io/#installation))