diff --git a/lectures/04.slim b/lectures/04.slim new file mode 100644 index 0000000..f34c927 --- /dev/null +++ b/lectures/04.slim @@ -0,0 +1,870 @@ +--- +layout: lecture +title: Databases +--- + +section.center data-background="#000" + h2.white Databases + +section.center data-background="#F00" + h2.white Questions + +section.center data-background="#F00" + h2.white What is a protocol? + +section.center data-background="#F00" + h2.white What are the essentials of HTTP? + +section.center data-background="#F00" + h2.white How can you serve content at a specific URL using Sinatra? + +section.center data-background="#FF0" + h2 Warning + +section.center data-background="#FF0" + p Lots of tables in this lecture! + +section.center data-background="#FF0" + p And we don't even know + +section.center data-background="#FF0" + p what we are talking about. + +section.center + h2 The right weapon + p + ' + (relational|object|graph|document) database + +section.center + h2 Relational databases + p PostgreSQL, MySQL, Microsoft SQL Server, SQLite, ... + +section.center data-background="#AED6FF" + h2.white SQLite + +section.center data-background="#000" + h2.white Databases + +section.center + h2 A home for your data + +section.center + h2 Data structure + +section.center + h2 Kind of like arrays and hashes + +section.center + h2 Much more complex + +section.center + h2 Optimized for storing lots of data + +section.center + h2 Optimized for retrieving lots of data very very fast + +section.center + h2 Supports building inner connections between parts of the data + +section.center + h2 Give me the thing that does something and is located somewhere along with its neighbours + +section.center + h2 Key components + +section.center + h2 Table (relation) + +section.center + h2 Column (attribute) + +section.center + h2 Row (record) + +section.center + h2 A table packs entities with common attributes + +section + pre + ' + +------------------------------------------------+ + | Student | + +------------+-----------+-----+-----------------+ + | FirstName | LastName | Age | Address | + +------------+-----------+-----+-----------------+ + | Joe | Somebody | 17 | Allen Street | + | Darrel | Addington | 15 | Bleecker Street | + | Dwenn | Charlton | 18 | Lenox Avenue | + +------------+-----------+-----+-----------------+ + +section.center + h2 Attribute data types + p TEXT, INTEGER, NUMERIC, REAL, NONE + +section.center + h2 String data types + pre + ' + +------------------+--------------------------------------+ + | CHAR(size) | Equivalent to TEXT (size is ignored) | + | VARCHAR(size) | Equivalent to TEXT (size is ignored) | + | TINYTEXT(size) | Equivalent to TEXT (size is ignored) | + | TEXT(size) | Equivalent to TEXT (size is ignored) | + | MEDIUMTEXT(size) | Equivalent to TEXT (size is ignored) | + | LONGTEXT(size) | Equivalent to TEXT (size is ignored) | + | NCHAR(size) | Equivalent to TEXT (size is ignored) | + | NVARCHAR(size) | Equivalent to TEXT (size is ignored) | + | CLOB(size) | Equivalent to TEXT (size is ignored) | + +------------------+--------------------------------------+ + +section.center + h2 Numeric data types + pre + ' + +------------------+-----------------------+ + | TINYINT | Equivalent to INTEGER | + | SMALLINT | Equivalent to INTEGER | + | MEDIUMINT | Equivalent to INTEGER | + | INT | Equivalent to INTEGER | + | INTEGER | Equivalent to INTEGER | + | BIGINT | Equivalent to INTEGER | + | INT2 | Equivalent to INTEGER | + | INT4 | Equivalent to INTEGER | + | INT8 | Equivalent to INTEGER | + | NUMERIC | Equivalent to NUMERIC | + | DECIMAL | Equivalent to NUMERIC | + | REAL | Equivalent to REAL | + | DOUBLE | Equivalent to REAL | + | DOUBLE PRECISION | Equivalent to REAL | + | FLOAT | Equivalent to REAL | + | BOOLEAN | Equivalent to NUMERIC | + +------------------+-----------------------+ + +section.center + h2 Date/time data types + pre + ' + +-----------+-----------------------+ + | DATE | Equivalent to NUMERIC | + | DATETIME | Equivalent to NUMERIC | + | TIMESTAMP | Equivalent to NUMERIC | + | TIME | Equivalent to NUMERIC | + +-----------+-----------------------+ + +section.center + h2 Large object data types + pre + ' + +-----------+-----------------------+ + | BLOB | Equivalent to NONE | + +-----------+-----------------------+ + +section.center + h2 Relating tables + +section.center + h2 primary key -> foreign key + +section.center + pre + ' + +------------------------------------------------+ + | Student | + +------------+-----------+-----+-----------------+ + | FirstName | LastName | Age | Address | + +------------+-----------+-----+-----------------+ + | Joe | Somebody | 17 | Allen Street | + | Darrel | Addington | 15 | Bleecker Street | + | Dwenn | Charlton | 18 | Lenox Avenue | + +------------+-----------+-----+-----------------+ + +section.center + pre + ' + +-------------------------------------------------------------------+ + | Student | + +------------+-----------+-----+-----------------+------------------+ + | FirstName | LastName | Age | Address | SchoolName | + +------------+-----------+-----+-----------------+------------------+ + | Joe | Somebody | 17 | Allen Street | Southview School | + | Darrel | Addington | 15 | Bleecker Street | Westview School | + | Dwenn | Charlton | 18 | Lenox Avenue | Southview School | + +------------+-----------+-----+-----------------+------------------+ + +section.center + pre + ' + +-----------------------------------------------------+ + | Student | + +----+------------+-----------+-----+-----------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-----------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 15 | Bleecker Street | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | + +----+------------+-----------+-----+-----------------+ + + +-------------------------------+ + | School | + +------------+------------------+ + | StudentId | SchoolName | + +------------+------------------+ + | 1 | Southview School | + | 2 | Westview School | + | 3 | Southview School | + +------------+------------------+ + +section.center + pre + ' + +-----------------------------------------------------+ + | Student | + +----+------------+-----------+-----+-----------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-----------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 15 | Bleecker Street | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | + +----+------------+-----------+-----+-----------------+ + + +--------------------------------------------------------------+ + | School | + +------------+------------------+------------------+-----------+ + | StudentId | School | Address | Type | + +------------+------------------+------------------+-----------+ + | 1 | Southview School | Ludlow Street | Secondary | + | 2 | Westview School | Rivington Street | Primary | + | 3 | Southview School | Ludlow Street | Secondary | + +------------+------------------+------------------+-----------+ + +section.center + pre + ' + +-----------------------------------------------------+ + | Student | + +----+------------+-----------+-----+-----------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-----------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 15 | Bleecker Street | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | + +----+------------+-----------+-----+-----------------+ + + +------------------------------------------------------+ + | School | + +----+------------------+------------------+-----------+ + | Id | Name | Address | Type | + +----+------------------+------------------+-----------+ + | 1 | Southview School | Ludlow Street | Secondary | + | 2 | Westview School | Rivington Street | Primary | + +----+------------------+------------------+-----------+ + + +-------------------------+ + | Student to School | + +------------+------------+ + | StudentId | SchoolId | + +------------+------------+ + | 1 | 1 | + | 2 | 2 | + | 3 | 1 | + +------------+------------+ + +section.center + h2 Normalization and denormalization + +section.center + h2 Normal forms + p First, Second, Third, Boyce–Codd, Fourth and Fifth + +section.center + h2 Indexes + +section.center + h2 Additional data structure built on top of your data + +section.center + h2 Greatly improve speed of retrieve operations at the cost of slower write operations + +section.center + h2 Transactions + +section.center + h2 You can define what an atomic operation is + +section.center + h2 Packing two write operations in a unit so that either both of them succeed or both of them fail + +section.center + h2 Bank transactions should not end in an invalid state no matter what + +section.center + h2 Structured Query Language + p is how you communicate with relational databases + +section.center + h2 Summer of '86 + +section.center + h2 + ' + SQL = DDL + DML + +section.center + h2 Data Definiton Language + p for defining data models and relations + +section.center + h2 Creating a database + pre + ' + CREATE DATABASE school; + +section.center + h2 Dropping a database + pre + ' + DROP DATABASE school; + +section.center + h2 Creating a table + pre + ' + CREATE TABLE Student(Id INTEGER, FirstName VARCHAR(255), LastName VARCHAR(255), Address VARCHAR(255)); + +section.center + h2 Changing a table + pre + ' + ALTER TABLE Student ADD Grade INTEGER; + +section.center + h2 Dropping the entries in a table + pre + ' + TRUNCATE TABLE Student; + +section.center + h2 Renaming a table + pre + ' + RENAME TABLE Student TO GraduatedStudent; + +section.center + h2 Dropping a table + pre + ' + DROP TABLE Student; + +section.center + h2 Create index on a column + pre + ' + CREATE INDEX AgeIndex ON Student (Age); + +section.center + h2 Create index on a column + pre + ' + CREATE UNIQUE INDEX UniqueIdIndex ON Student (id); + +section.center + h2 Data Manipulation Language + p for inserting, retrieving and altering data + +section.center + pre + ' + +-----------------------------------------------------+ + | Student | + +----+------------+-----------+-----+-----------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-----------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 15 | Bleecker Street | + +----+------------+-----------+-----+-----------------+ + +section.center + h2 Inserting a record + pre + ' + INSERT INTO Student(FirstName, LastName, Age, Address) VALUES ('Dwenn', 'Charlton', 18, 'Lenox Avenue'); + +section.center + pre + ' + +-----------------------------------------------------+ + | Student | + +----+------------+-----------+-----+-----------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-----------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 15 | Bleecker Street | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | + +----+------------+-----------+-----+-----------------+ + +section.center + h2 Updating records + pre + ' + UPDATE Student + SET Address='Washington Street',Age=16 + WHERE FirstName='Darrel' AND SecondName='Addington'; + +section.center + pre + ' + +-------------------------------------------------------+ + | Student | + +----+------------+-----------+-----+-------------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-------------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 16 | Washington Street | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | + +----+------------+-----------+-----+-------------------+ + +section.center + h2 Deleting records + pre + ' + DELETE FROM Student WHERE Id=3; + +section.center + pre + ' + +-------------------------------------------------------+ + | Student | + +----+------------+-----------+-----+-------------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-------------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 16 | Washington Street | + +----+------------+-----------+-----+-------------------+ + +section.center + h2 Retrieving records + pre + ' + SELECT * FROM Student WHERE FirstName='Joe'; + +section.center + pre + ' + +----+------------+-----------+-----+-------------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-------------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + +----+------------+-----------+-----+-------------------+ + +section.center + h2 Retrieving records + pre + ' + SELECT LastName, Age FROM Student WHERE FirstName='Joe'; + +section.center + pre + ' + +-----------------+-----+ + | LastName | Age | + +-----------------+-----+ + | Somebody | 17 | + +-----------------+-----+ + +section.center + h2 Ordering results + pre + ' + SELECT * FROM Student ORDER BY Age DESC; + +section.center + pre + ' + +----+------------+-----------+-----+-------------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-------------------+ + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 16 | Washington Street | + +----+------------+-----------+-----+-------------------+ + +section.center + h2 Commit a transaction + pre + ' + BEGIN TRANSACTION; + CREATE TABLE Student(FirstName VARCHAR(255), LastName VARCHAR(255), Age INTEGER, Address VARCHAR(255)); + INSERT INTO Student(FirstName, LastName, Age, Address) VALUES ('Joe', 'Somebody', 17, 'Allen Street'); + INSERT INTO Student(FirstName, LastName, Age, Address) VALUES ('Dwenn', 'Charlton', 18, 'Lenox Avenue'); + COMMIT; + +section.center + h2 Combining two queries + +section.center + pre + ' + (SELECT * FROM Student WHERE Age > 15) + UNION + (SELECT * FROM Student WHERE Age < 18) + +section.center + pre + ' + +----+------------+-----------+-----+-------------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-------------------+ + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 16 | Washington Street | + +----+------------+-----------+-----+-------------------+ + +section.center + pre + ' + (SELECT * FROM Student WHERE Age > 16) + INTERSECT + (SELECT * FROM Student WHERE Age < 18) + +section.center + pre + ' + +----+------------+-----------+-----+-------------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-------------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + +----+------------+-----------+-----+-------------------+ + +section.center + pre + ' + (SELECT * FROM Student WHERE Age > 15) + EXCEPT + (SELECT * FROM Student WHERE Address='Lenox Avenue') + +section.center + pre + ' + +----+------------+-----------+-----+-------------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-------------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 16 | Washington Street | + +----+------------+-----------+-----+-------------------+ + +section.center + h2 UNION ALL, INTERSECT ALL and EXCEPT ALL preserve duplicate rows + +section.center data-background="#FFAED6" + h2 So why relational? + +section.center + pre + ' + +-----------------------------------------------------+ + | Student | + +----+------------+-----------+-----+-----------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-----------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 15 | Bleecker Street | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | + +----+------------+-----------+-----+-----------------+ + + +---------------------------------------------------------------+ + | School | + +------------+------------------+------------------+------------+ + | StudentId | SchoolName | SchoolAddress | SchoolType | + +------------+------------------+------------------+------------+ + | 1 | Southview School | Ludlow Street | Secondary | + | 2 | Westview School | Rivington Street | Primary | + | 5 | Northview School | Fulton Street | Primary | + +------------+------------------+------------------+------------+ + +section.center + h2 Retrieve all student along with the school they go to + pre + ' + SELECT * FROM Student LEFT [OUTER] JOIN School ON Student.Id=School.StudentId + +section.center + pre + ' + +----+------------+-----------+-----+-----------------+----------+------------------+------------------+------------+ + | Id | FirstName | LastName | Age | Address |StudentId | SchoolName | SchoolAddress | SchoolType | + +----+------------+-----------+-----+-----------------+----------+------------------+------------------+------------+ + | 1 | Joe | Somebody | 17 | Allen Street | 1 | Southview School | Ludlow Street | Secondary | + | 2 | Darrel | Addington | 15 | Bleecker Street | 2 | Westview School | Rivington Street | Primary | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | 3 | NULL | NULL | NULL | + +----+------------+-----------+-----+-----------------+----------+------------------+------------------+------------+ + +section.center + h2 Retrieve all schools along with their students + pre + ' + SELECT * FROM Student RIGHT [OUTER] JOIN School ON Student.Id=School.StudentId + +section.center + pre + ' + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + | Id | FirstName | LastName | Age | Address |StudentId | SchoolName | SchoolAddress | SchoolType | + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + | 1 | Joe | Somebody | 17 | Allen Street | 1 | Southview School | Ludlow Street | Secondary | + | 2 | Darrel | Addington | 15 | Bleecker Street | 2 | Westview School | Rivington Street | Primary | + | NULL | NULL | NULL | NULL | NULL | 5 | Northview School | Fulton Street | Primary | + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + +section.center + h2 Retrieve all students and matching schools + pre + ' + SELECT * FROM Student JOIN School ON Student.Id=School.StudentId + +section.center + pre + ' + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + | Id | FirstName | LastName | Age | Address |StudentId | SchoolName | SchoolAddress | SchoolType | + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + | 1 | Joe | Somebody | 17 | Allen Street | 1 | Southview School | Ludlow Street | Secondary | + | 2 | Darrel | Addington | 15 | Bleecker Street | 2 | Westview School | Rivington Street | Primary | + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + +section.center + h2 Retrieve all schools and all students, keeping relations + pre + ' + SELECT * FROM Student FULL [OUTER] JOIN School ON Student.Id=School.StudentId + +section.center + pre + ' + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + | Id | FirstName | LastName | Age | Address |StudentId | SchoolName | SchoolAddress | SchoolType | + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + | 1 | Joe | Somebody | 17 | Allen Street | 1 | Southview School | Ludlow Street | Secondary | + | 2 | Darrel | Addington | 15 | Bleecker Street | 2 | Westview School | Rivington Street | Primary | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | 3 | NULL | NULL | NULL | + | NULL | NULL | NULL | NULL | NULL | 5 | Northview School | Fulton Street | Primary | + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + +section.center + h2 Retrieve cartesian product of all schools and all students + pre + ' + SELECT * FROM Student CROSS JOIN School ON Student.Id=School.StudentId + +section.center + pre + ' + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + | Id | FirstName | LastName | Age | Address |StudentId | SchoolName | SchoolAddress | SchoolType | + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + | 1 | Joe | Somebody | 17 | Allen Street | 1 | Southview School | Ludlow Street | Secondary | + | 1 | Joe | Somebody | 17 | Allen Street | 2 | Westview School | Rivington Street | Primary | + | 1 | Joe | Somebody | 17 | Allen Street | 5 | Northview School | Fulton Street | Primary | + | 2 | Darrel | Addington | 15 | Bleecker Street | 1 | Southview School | Ludlow Street | Secondary | + | 2 | Darrel | Addington | 15 | Bleecker Street | 2 | Westview School | Rivington Street | Primary | + | 2 | Darrel | Addington | 15 | Bleecker Street | 5 | Northview School | Fulton Street | Primary | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | 1 | Southview School | Ludlow Street | Secondary | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | 2 | Westview School | Rivington Street | Primary | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | 5 | Northview School | Fulton Street | Primary | + +------+------------+-----------+------+-----------------+----------+------------------+------------------+------------+ + +section.center + h2 Views + +section.center + h2 View are virtual tables + +section.center + pre + ' + CREATE VIEW LegalStudents AS SELECT FirstName, LastName FROM Student WHERE Age > 18; + +section.center + pre + ' + +------------------------+ + | LegalStudents | + +------------+-----------+ + | FirstName | LastName | + +------------+-----------+ + | Joe | Somebody | + | Darrel | Addington | + | Dwenn | Charlton | + +------------+-----------+ + +section.center + pre + ' + SELECT * FROM LegalStudents; + +section.center + pre + ' + CREATE OR REPLACE VIEW LegalStudents AS SELECT FirstName, Address FROM Student WHERE Age > 18; + +section.center + pre + ' + +------------------------------+ + | LegalStudents | + +------------+-----------------+ + | FirstName | Address | + +------------+-----------------+ + | Joe | Allen Street | + | Darrel | Bleecker Street | + | Dwenn | Lenox Avenue | + +------------+-----------------+ + +section.center + pre + ' + DROP VIEW LegalStudents; + +section.center + h2 Agregates + +section.center + h2 SUM, AVG, MIN, MAX, COUNT + +section.center + pre + ' + +-----------------------------------------------------+ + | Student | + +----+------------+-----------+-----+-----------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-----------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 15 | Bleecker Street | + | 3 | Dwenn | Charlton | 18 | Lenox Avenue | + +----+------------+-----------+-----+-----------------+ + +section.center + pre + ' + SELECT COUNT(*) FROM Student + +section.center + pre + ' + +---+ + | 3 | + +---+ + +section.center + pre + ' + SELECT AVG (Age) as Average FROM Student + +section.center + pre + ' + +---------+ + | Average | + +---------+ + | 16.6667 | + +---------+ + +section.center + h2 DISTINCT + +section.center + pre + ' + +-------------------------------+ + | School | + +------------+------------------+ + | StudentId | SchoolName | + +------------+------------------+ + | 1 | Southview School | + | 2 | Westview School | + | 3 | Southview School | + +------------+------------------+ + +section.center + pre + ' + SELECT COUNT(DISTINCT SchoolName) FROM School + +section.center + pre + ' + +---+ + | 2 | + +---+ + +section.center + h2 Grouping + +section.center + pre + ' + +-----------------------------------------------------+ + | Student | + +----+------------+-----------+-----+-----------------+ + | Id | FirstName | LastName | Age | Address | + +----+------------+-----------+-----+-----------------+ + | 1 | Joe | Somebody | 17 | Allen Street | + | 2 | Darrel | Addington | 15 | Bleecker Street | + | 3 | Dwenn | Charlton | 18 | Allen Street | + +----+------------+-----------+-----+-----------------+ + +section.center + pre + ' + SELECT Address, SUM(Age) AS CompositeAge FROM Student GROUP BY Address + +section.center + pre + ' + +-----------------+--------------+ + | Address | CompositeAge | + +-----------------+--------------+ + | Allen Street | 35 | + | Bleecker Street | 15 | + +-----------------+--------------+ + +section.center + h2 We can use multiple attributes in the GROUP BY clause + +section.center + h2 We can select only columns that will be used in the GROUP BY clause and agregates + +section.center + h2 We cannot use agregates in the WHERE clause, that's why we have HAVING + +section.center + pre + ' + SELECT Address, SUM(Age) AS CompositeAge FROM Student GROUP BY Address HAVING CompositeAge > 30 + +section.center + pre + ' + +-----------------+--------------+ + | Address | CompositeAge | + +-----------------+--------------+ + | Allen Street | 35 | + +-----------------+--------------+ + +section.center + pre + ' + SELECT ... FROM ... JOIN ... ON ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... + +section.center + h2 Back to our microblogs + +section.center + h2 gem install sqlite3 + +section.center + h2 Experiment and have fun! + +section.center + img.inline(src="/images/hack_bulgaria.png")