Databases
CIS 193 – Go Programming
Prakhar Bhandari, Adel Qalieh
CIS 193
Prakhar Bhandari, Adel Qalieh
CIS 193
What is SQL?
What is a relational database?
Tables in a relational database can form and define relations between the data
Tables have a schema, which is the underlying skeleton structure of the database
Data Types
Here, we can specify the table name, columns names (with types), and other restrictions
CREATE TABLE movies ( id INTEGER PRIMARY KEY, title TEXT, director TEXT, year INTEGER, length_minutes INTEGER );
Syntax
column DataType TableConstraint DEFAULT default_value,
TableConstraint: For example, PRIMARY KEY, UNIQUE, NOT NULL, FOREIGN KEY, etc
INSERT INTO boxoffice (movie_id, rating, sales_in_millions) VALUES (1, 9.9, 283742034 / 1000000), VALUES (2, 4.9, 563732214 / 1000000);
Specifying the columns is optional, otherwise it will follow the structure of the table
Syntax
SELECT column, another_column, … FROM mytable WHERE condition AND/OR another_condition AND/OR …;
For example, to get all the movies directed by Wes Anderson, we can do:
SELECT title, director FROM movies WHERE director = "John Lasseter";
Syntax
SELECT column, another_column, … FROM mytable WHERE condition(s) ORDER BY column ASC/DESC LIMIT num_limit OFFSET num_offset;L
Delete Syntax
DELETE FROM mytable WHERE condition;
Update Syntax
UPDATE mytable SET column = value_or_expr, other_column = another_value_or_expr, … WHERE condition;
Used for multi-table queries
Syntax of an inner join:
SELECT column, another_table_column, … FROM mytable INNER JOIN another_table ON mytable.id = another_table.id WHERE condition(s) ORDER BY column, … ASC/DESC LIMIT num_limit OFFSET num_offset;
You can use this SQL knowledge with Go to interact with databases with database/sql
import ( "database/sql" _ "github.com/go-sql-driver/mysql" // or some other driver )
This package supports SQL syntax
db, err := sql.Open("sqlite3", "./test.db") defer db.Close() _, err = db.Exec("CREATE TABLE movie_info ( id INTEGER, name VARCHAR(32), rating FLOAT )") rows, err := db.Query("SELECT * FROM movie_info")
Object-relational mapping is a way of converting data between native data structures from different languages. Translation: "object" = your programming language, "relational" = your relational database, and "mapping" = the bridge between them.
In this case, we are talking about converting between Go types and SQL types.
There is no standard ORM in the standard library. Here are some options:
Install
go get -u github.com/jinzhu/gorm
Import
Choose a SQL dialect, in this case SQLite. Good options include SQLite, MySQL, and PostgreSQL.
import ( "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/sqlite" )
Connect to database
The parameters use depend entirely on your dialect. See the GORM documentation.
db, err := gorm.Open("sqlite3", "/tmp/gorm.db") defer db.Close()
Embed Struct
type Product struct { gorm.Model Name string Price uint }
gorm.Model
provides the fields ID
, CreatedAt
, UpdatedAt
, and DeletedAt
Struct tags
Use struct tags to designate column types. There are many options, see documentation.
type Product struct { gorm.Model Name string `gorm:"size:255"` Price uint }
To add data to your database, simply use db.Create(...)
product := Product{Name: "DigitalOcean Basic Droplet", Price: 5} db.Create(&product)
To query for data from the database, use db.First(...)
and db.Find(...)
var product Product db.First(&product)
To make sophisticated queries, you can use plain SQL or struct/maps.
db.Where("name = ?", "Amazon Web Services").First(&product) db.Where(&Product{Name: "Amazon Web Services").First(&product) db.Where(map[string]interface{}{"name": "Amazon Web Services"}).First(&product)
These 3 methods are equivalent and result in the exact same SQL query:
SELECT * FROM products WHERE name = "Amazon Web Services" LIMIT 1;
To delete an entry from the database, use db.Delete(...)
db.Delete(&product)
To update a model, use db.Save(...)
product.Price = 120 db.Save(&product)
To update a single field, there is a shortcut: model.Update(field, value)
db.Model(&product).Update("price", 80)
The biggest advantage of an ORM is with linked models. Relational databases are best with related models (duh!).
There are many types of relationships - belongs to, has many, many to many, etc.
To actually use these, refer to the GORM documentation. Here's a simple example:
type User struct { gorm.Model Products []Product } db.Model(&user).Related(&products)
In this example, a user has many products, but the products do not belong in any way to a user. Thus, we can implement a "cart" feature to the user by adding a "has many" type relationship.
What if your database schema changes?
Hint: It always changes!
To migrate the schema of the current type's definition, use db.AutoMigrate(...)
db.AutoMigrate(&Product{})
You can also migrate multiple models at once:
db.AutoMigrate(&Product{}, &User{})
Important: the table name is the pluralized version of the struct name. For example, Product
will have table name products
.
Important: AutoMigrate
will only create tables, columns, and indexes, but will not make any other changes automatically (ex: deleting a column).