- Notifying instructors if late
10am, 30 minutes
10:30, 30 minutes
11:00, 40 minutes
- SQL stands for Structured Query Language. SQL is just a way of talking to relational databases.
- There are many different instances of SQL databases, each with tiny differences amongst themselves. The differences are so minute we won't go over them here, but if you'd like to look them up, go ahead.
- PostgreSQL
- MySQL
- SQLite
- Proprietary software like Oracle or Microsoft SQL Server
- There are lots and lots of SQL data types, many more than in Ruby. But there are a couple that we use most of the time:
- Boolean
- Integer
- Float
- Text/VARCHAR
- NULL
- Date
- Time
- And many more...
- All statements end with a semicolon
- White space doesn't matter
- Use only single quotes to denote strings; double quotes are for table or column identifiers
- Group things with parentheses
- Keywords tend to be uppercased (although this is just a convention)
- http://www.postgresql.org/docs/9.4/interactive/index.html
- Style Guide: http://leshazlewood.com/software-engineering/sql-style-guide/
EXERCISE: Using your ERDs/Database models from last night's homework, go through the fields and decide what data type they should be. Use the PG docs to help.
BREAK: 10 minutes
11:50, 15 minutes
$ brew update
$ brew doctor
$ brew install postgresql
$ initdb /usr/local/var/postgres -E utf8
$ mkdir -p ~/Library/LaunchAgents
$ cp /usr/local/Cellar/postgresql/<<<YOUR_PSQL_VERSION_NUMBER>>>/homebrew.mxcl.postgresql.plist ~/Library/LaunchAgents/
$ launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
$ gem install pg
If something goes wrong during the Homebrew installation, you can use http://postgresapp.com/ instead
12:05, 30 minutes
- First, let's open up
psql
, which is a REPL for Postgres, a type of SQL database we have installed on our computers - If we type
\l
, we'll be able to see all the databases Postgres has already. Postgres has already created a couple databases with metadata that it uses internally, which we can see here. - To create our own database, we can type
CREATE DATABASE wdi;
- To do anything with our database, first we need to connect to it. We do that by typing
\c wdi
. - If we type
\d
, we'll see there are no tables - We can create a table by using the following syntax
CREATE TABLE students (
id SERIAL PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
age INT NOT NULL,
ss_num INT NOT NULL UNIQUE
);
- The format on each of these lines for creating a field is
field_name TYPE_OF_FIELD CONSTRAINT (CONSTRAINT 2) (CONSTRAINT 3)
- Constraints are the rules we apply to fields on the database to make sure our database stays clean and in a valid state.
- Some of the most popular constraints are
PRIMARY KEY
,NOT NULL
, andUNIQUE
. There are others that you should check out.
- The format on each of these lines for creating a field is
EXERCISE: Create a database named after the app you modeled for last night's homework, then create at least 2 of the tables with the appropriate fields and constraints
LUNCH: 1 Hour
1:35, 40 minutes
INSERT INTO wdi (first_name, last_name, age) VALUES ('Sean', 'Shannon', 26)
SELECT * FROM wdi
- The
WHERE
clause- To use the where clause, we need a field to compare, an operator specifying the type of comparison to be made, and a value that represents our criterion
SELECT * FROM wdi WHERE last_name = 'Shannon'
SELECT * FROM wdi WHERE age >= 25
UPDATE students SET ss_num = 987654321 WHERE age > 25;
DELETE FROM students WHERE age > 25;
2:15, 30 minutes
- Inner Join
- Combines only the records that match both sides
- Left/Right Join
- Combines all the records of one side with the matching record from the other side, and fills in null for remaining
- Outer Join
- Combines all record of both sides with matching record from the other side, and fills in null for remaining. Potential for duplicate data.
- http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
- http://blog.flatironschool.com/post/34096752495/sql-joins-explained-visually-the-3-ring-binder-model
2:45, 20 minutes
- A database index is a data structure that orders itself by some criterion, and then maps the ordered data in the index to the unordered data in tables
- Dewey Decimal System analogy
- Database indices should be created for any field of data you will frequently query, or search for. If the field is unordered and you attempt to search through it, it is similar to looking through a library without any idea of where the book you want is
- Creating too many database indices can be harmful because these indexes take up space in memory, and so creating so many indices that they don't fit in memory will make your application's performance suffer
CREATE INDEX index_name ON table_name ( column1, column2.....);
BREAK: 10 minutes
3:15, 40 minutes
-
For now we can simply
require "pg" conn = PG.connect(:hostaddr => "127.0.0.1", :port => 5432, :dbname => "wdi") res = conn.exec("SELECT * FROM students") res.each do |item| puts item end
-
The PG object allows us to access and interface with the Postgres database. It is the API (or bridge) from our app to the database.
-
Here, we're saving the result of the PG connection to a variable named
conn
, then we're using theexec
method of that object to send a SQL query to the database. Finally, we're looping through the results of the query andputs
-ing them.
EXERCISE: Write a simple program that will take input from the user and insert their information as a row in the students
table we created using the PG object to communicate with the database.
-
SQL injection is one of the most dangerous and most prominent types of attacks on the web. It is also one of the easiest to stop.
-
SQL injection occurs when user input is not "sanitized" first, meaning it is possible for the user to type characters that are not properly escaped and can control the actual SQL itself
-
SQL injection allows malicious users to gain access to your database which has potentially private and valuable information about your users and your application, and then the hacker can even lock you out of the database
-
To prevent this, we can use prepared statements, like so:
conn.prepare('insert_student_statement', 'INSERT INTO students (first_name, last_name, age, ss_num) values ($1, $2, $3, $4)') conn.exec_prepared('insert_student_statement', [ 'Mikael', 'Davis', 25, 649204729 ])
-
Prepared statements sanitize our data by escaping it, which means it will prevent any quotation marks from being interpreted as control characters, and instead will interpret them literally as characters in a string. This prevents the hacker from being able to influence our program.
3:55, Remainder of class
Using SQL and prepared statements, create a Ruby class for Student
and add class methods that would implement the basic CRUD functionality to interact with a database by calling a Ruby method on the class
BONUS: Try thinking of additional helpful SQL commands that you can implement to act on multiple records at a time, and implement those.
DOUBLE BONUS: Try making an abstract class that can be extended by any subclass that wants to use these SQL methods. You'll have to update your SQL statements!