CRUD operations with MSSQL Server
CRUD operations with MSSQL Server
Golang give us a generic interface to work with SQL Databases.
But it’s crucial to use a database driver altogether, check the drivers list: Drivers List
In this article it will be used this driver MSSQL Server Driver (denisenkom)
Setting the environment up
It’s necessary to create 3 tables on the database in order to run the examples.
create table movie (
id int identity(1, 1) not null,
title nvarchar(255),
running_time int,
constraint PK_MOVIE primary key(id)
)
create table actor (
id int identity(1, 1) not null,
name nvarchar(255),
constraint PK_ACTOR primary key(id)
)
create table movie_actor (
id int identity(1, 1) not null,
movie_id int,
actor_id int,
constraint PK_MOVIE_ACTOR primary key(id),
constraint FK_MOVIE foreign key(movie_id) references movie(id),
constraint FK_ACTOR foreign key(actor_id) references actor(id)
)
It’s necessary to have these 3 structs too
type Movie struct {
Id int
Title string
RunningTime int
}
type Actor struct {
Id int
Name string
}
type MovieActor struct {
Id int
MovieId int
ActorId int
}
Building up the connection string
In order to help us to build the connection string with MSSQL Server, lets use the package net/url*.
Further information about the package net/url click here
query := url.Values{}
query.Add("app name", "myAppName")
query.Add("database", "movies")
u := &url.URL{
Scheme: "sqlserver",
User: url.UserPassword("golang", "gopass"),
Host: fmt.Sprintf("%s:%d", "192.168.1.34", 1433),
RawQuery: query.Encode(),
}
Then we can open the connection with the database:
db, err := sql.Open("sqlserver", u.String())
if err != nil {
panic(err)
}
defer db.Close()
Inserting a row on the database
We’ll come up with a function to insert an actor on the database:
func insertActor(db *sql.DB, actor *Actor) (int, error) {
stmt, err := db.Prepare("INSERT INTO ACTOR(NAME) OUTPUT INSERTED.id VALUES (@p1)")
if err != nil {
return 0, err
}
defer stmt.Close()
var lastInsertedId int
err = stmt.QueryRow(actor.Name).Scan(&lastInsertedId)
if err != nil {
return 0, nil
}
return lastInsertedId, nil
}
In this instruction “INSERT INTO ACTOR(NAME) OUTPUT INSERTED.id VALUES (@p1)”, we use OUTPUT INSERTED.id to get the id that has been generated by the database, since it’s a generated automatically sequential field.
Having this function ready, we’ll be able to call it.
lastId, err := insertActor(db, a)
if err != nil {
panic(err)
}
fmt.Printf("Last actor inserted Name: %s Id: %d", a.Name, lastId)
>> Last actor inserted - Name: Alfredo Pacino Id: 1
Function to insert a movie
func insertMovie(db *sql.DB, movie *Movie) (int, error) {
stmt, err := db.Prepare("INSERT INTO MOVIE(TITLE, RUNNING_TIME) OUTPUT INSERTED.id VALUES (@p1, @p2)")
if err != nil {
return 0, err
}
defer stmt.Close()
var lastInsertedId int
err = stmt.QueryRow(movie.Title, movie.RunningTime).Scan(&lastInsertedId)
if err != nil {
return 0, err
}
return lastInsertedId, nil
}
Now we are able to call the function to insert a movie
m := &Movie{
Title: "Scent of a Woman",
RunningTime: 142,
}
lastId, err := insertMovie(db, m)
if err != nil {
panic(err)
}
fmt.Printf("Last movie inserted - Title: %s - Running Time: %d - Id: %d", m.Title, m.RunningTime, lastId)
>> Last movie inserted - Title: Scent of a Woman - Running Time: 142 Id: 1
Altering a database value
The update function will return the number of updated rows and if there was some error:
In order to get the number of updated rows we can use the RowsAffected() function
func updateActor(db *sql.DB, actorId int, name string) (int64, error) {
stmt, err := db.Prepare("UPDATE ACTOR SET NAME = @p1 WHERE ID = @P2")
if err != nil {
return 0, err
}
defer stmt.Close()
result, err := stmt.Exec(name, actorId)
if err != nil {
return 0, nil
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return 0, err
}
return rowsAffected, nil
}
updatedRows, err := updateActor(db, 1, "Al Pacino")
if err != nil {
panic(err)
}
fmt.Printf("Number of updated rows: %d", updatedRows)
>> Number of updated rows: 1
Retrieving values from the database
func getActor(db *sql.DB, actorId int) (*Actor, error) {
stmt, err := db.Prepare("SELECT ID, NAME FROM ACTOR WHERE ID = @p1")
if err != nil {
return nil, err
}
defer stmt.Close()
var a Actor
err = stmt.QueryRow(actorId).Scan(&a.Id, &a.Name)
if err != nil {
return nil, err
}
return &a, nil
}
a, err := getActor(db, 1)
if err != nil {
panic(err)
}
fmt.Printf("Actor Id: %d - Actor Name: %s", a.Id, a.Name)
>> Actor Id: 1 - Actor Name: Al Pacino
Deleting rows from the database
func deleteActor(db *sql.DB, actorId int) (int64, error) {
stmt, err := db.Prepare("DELETE FROM ACTOR WHERE ID = @p1")
if err != nil {
return 0, err
}
defer stmt.Close()
result, err := stmt.Exec(actorId)
if err != nil {
return 0, err
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return 0, err
}
return rowsAffected, nil
}
deletedRows, err := deleteActor(db, 5)
if err != nil {
panic(err)
}
fmt.Printf("Number os deleted actors: %d", deletedRows)
>> Number of deleted actors: 1
Joining an actor to a movie
func insertActorMovie(db *sql.DB, movieId int, actorId int) (int, error) {
stmt, err := db.Prepare("INSERT INTO MOVIE_ACTOR(MOVIE_ID, ACTOR_ID) OUTPUT INSERTED.id VALUES(@p1, @p2)")
if err != nil {
return 0, err
}
defer stmt.Close()
var lastInsertedId int
err = stmt.QueryRow(movieId, actorId).Scan(&lastInsertedId)
if err != nil {
return 0, err
}
return lastInsertedId, nil
}
lastInsertedId, err := insertActorMovie(db, 1, 1)
if err != nil {
panic(err)
}
fmt.Printf("Last ID inserted: %d", lastInsertedId)
>> Last ID inserted: 1
Retrieving all actors who participated in a movie
func getMovieAndActors(db *sql.DB, movieId int) (*MovieActors, error) {
stmt, err := db.Prepare(`
select
b.id ActorId,
b.name ActorName,
c.id MovieId,
c.title MovieTitle,
c.running_time RunningTime
from movie_actor a
inner join actor b on a.actor_id = b.id
inner join movie c on a.movie_id = c.id
where a.movie_id = @p1
`)
if err != nil {
return nil, err
}
defer stmt.Close()
var a Actor
var m Movie
var movieActors MovieActors
rows, err := stmt.Query(movieId)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
err = rows.Scan(&a.Id, &a.Name, &m.Id, &m.Title, &m.RunningTime)
if movieActors.Movie.Id == 0 {
movieActors.Movie = m
}
movieActors.Actors = append(movieActors.Actors, a)
}
return &movieActors, nil
}
m, err := getMovieAndActors(db, 1)
if err != nil {
panic(err)
}
for _, v := range m.Actors {
fmt.Printf("Movie info Id: %d - Title: %s - Running Time: %d - Actor Info Id: %d - Name: %s\n", m.Id, m.Title, m.RunningTime, v.Id, v.Name)
}
>> Movie info Id: 1 - Title: Scent of a Woman - Running Time: 142 - Actor Info Id: 1 - Name: Al Pacino
>> Movie info Id: 1 - Title: Scent of a Woman - Running Time: 142 - Actor Info Id: 2 - Name: Chris O'Donnel
>> Movie info Id: 1 - Title: Scent of a Woman - Running Time: 142 - Actor Info Id: 3 - Name: James Rebhorn
>> Movie info Id: 1 - Title: Scent of a Woman - Running Time: 142 - Actor Info Id: 4 - Name: Gabrielle Anwar