JRehkemper.de

Use PostgreSQL Connection in GO with raw SQL Statements

If you want to work with a database, you can use either a ORM like GORM or raw SQL Statements. Both have pros and cons.
ORM will make you worry less about structs since it automatically converts the results of the query to objects.
Raw SQL on the other hands has the advantage if you want to build more complex queries, since you don’t have to translate them into ORM functions.
What better suits you, is quite a personal decision.

I will concentrate on raw SQL for now.

Connect to PostgreSQL

You will need two packages for that.
database/sql from the standard library and pg. We will only need to install the pg package.

go get github.com/go-pg/pg/v10
go get -u github.com/lib/pq

Let’s create a database-package to manage our connection.

package database

import (
	"database/sql"
	
	_ "github.com/lib/pq"
)

func Connect() *sql.DB {
	connStr := "user=<db-user> password=<password> host=<db-host> dbname=<database-name> sslmode=disable"

	db, err := sql.Open("postgres", connStr)
	if err != nil {
		log.Panic(err)
	}
	return db
}

Notice the Underscore in front of the import of pg? This is necessary since we don’t interact with the package directly and go will see it as unused. With the Underscore we prevent this check.

If you want to use ssl to encrypt your connection set sslmode to either verify-ca, verify-full or simply require. For more detailed information, habe a look at the official documentation.

Execute Queries

Select Data

Next we will query some data.

func GetUsers() {
	// Create database connection
	db := database.Connect()
	// Close it once it is no longe in use
	defer db.Close()

	// define raw SQL Query
	// Parameter are done like $1, $2, $3...  
	query := `SELECT
					"id",
					"username",
					"age"
				FROM "users"
				WHERE 
					"username" = $1 
					AND 
					age > $2
				;`
	// Execute Query
	// Give parameters as args
	rows, err := db.Query(query, 'Steve', 18)
	// Check for errors
	if err != nil {
		log.Fatal(err)
	}
	// Free rows-object once not longer in user
	defer rows.Close()

	// Create empty arry of type User
	var users = make([]User, 0)
	// Iterate over all rows
	for rows.Next() {
		// Create empty user object
		var u User
		// Read data from SQL-Query into User-object
		rows.Scan(
			&u.Id,
			&u.Username,
			&u.Age
		)
		// Add user to array
		users = append(users, u)
	}
}

Insert or Update Data

If you want to insert or Update data you might want to get the number of affected rows back. This can be done like so.

func InsertUser() int {
	// Connect to database
	db := database.Connect()
	// Close Connection later
	defer db.Close()

	// Define raw SQL query
	query := `INSERT INTO "users" ("username", "age")
				VALUES ($1, $2);`
	// Execute Query with paramters
	res, err := db.Exec(query, 'Jeany', 21)
	// Error handling
	if err != nil {
		log.Fatal(error)
	}

	// Get the number of affected rows
	rowCount, err := res.RowsAffected()
	if err != nil {
		log.Fatal(err)
	}

	// return number
	return rowCount
}
profile picture of the author

Jannik Rehkemper

I'm an professional Linux Administrator and Hobby Programmer. My training as an IT-Professional started in 2019 and ended in 2022. Since 2023 I'm working as an Linux Administrator.