> For the complete documentation index, see [llms.txt](https://davidwinalda94.gitbook.io/mastering-golang/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://davidwinalda94.gitbook.io/mastering-golang/sql.md).

# SQL

Go menyediakan [package](https://golang.org/pkg/database/sql/) `database/sql` untuk dapat menggunakan SQL pada Go. Kita perlu untuk menginstal driver database baik itu `MySQL` , `sqlite` , `postgres` , dan lainnya pada local komputer kita dan juga pada aplikasi Go.

Untuk driver database kita memerlukan [package](https://github.com/golang/go/wiki/SQLDrivers) external. Kamu dapat menginstal sesuai dengan driver yang ingin digunakan. Pada sesi ini kita akan menggunakan driver database MySQL.&#x20;

### Instalasi Driver

Kita akan menggunakan [package](https://github.com/go-sql-driver/mysql/) database driver MySQL. Silahkan melakukan instalasi pada aplikasi Go yang sudah dibuat:

```go
go get -u github.com/go-sql-driver/mysql
```

### Setup Database

Untuk menjalankan database SQL dengan driver [MySQL](https://dev.mysql.com/downloads/mysql/), pastikan kamu telah menginstal MySQL pada local komputer. Setelah itu kita bisa mengakses MySQL melalui command line ataupu GUI seperti [Dbeaver](https://dbeaver.io/) dan [Sequel Pro](https://www.sequelpro.com/).

Pada contoh ini kita akan menggunakan command line untuk memanipulasi data query SQL.

Untuk mengakses `MySQL` , ketik perintah berikut ini:

```
mysql -u root -p
```

Selanjutnya masukkan query berikut ini untuk membuat sebuah database bernama `goschool` :

```
CREATE DATABASE goschool;
```

Kita juga harus memilih database yang ingin digunakan:

```
USE goschool;
```

Selanjutnya kita akan membuat table dan column serta memasukkan beberapa data:

```
CREATE TABLE IF NOT EXISTS students (
  id int(5) NOT NULL AUTO_INCREMENT,
  fullname varchar(255) NOT NULL,
  age int(11) NOT NULL,
  batch varchar(100) NOT NULL,
  PRIMARY KEY (id)
);

INSERT INTO students (id, fullname, age, batch) VALUES
(1, 'Wisma Eka', 24, 'adorable'),
(2, 'Yudis', 22, 'brilliant'),
(3, 'Sukisno', 35, 'creative'),
(4, 'Guntur', 30, 'dilligent');
```

### Membaca data dari MySQL Server

Kita sudah memiliki data pada database MySQL yaitu table `students` yang berisi 4 baris data. Selanjutnya kita akan membaca dan menampilkan data dari MySQL Server.

Kita perlu mengimport package `database/sql` dan juga `_ "github.com/go-sql-driver/mysql"` . Kita lihat ada tanda `_` yang berarti package tersebut kita butuhkan namin tidak kita gunakan secara langsung pada kode kita.

Selanjutnya kita akan membuat `struct` yang menggambarkan struktur data kita pada table database:

```go
type Student struct {
	ID       int
	Fullname string
	Age      int
	Batch    string
}
```

Kita butuh untuk memastikan terlebih dahulu aplikasi Go kita telah terhubung dengan MySQL server. Untuk itu kita akan membuat fungsi `connect()` dan menggunakan fungsi `sql.Open` untuk meregistrasi data MySQL server yang kita gunakan:

```go
sql.Open("mysql", "user:password@/dbname")
```

```go
func connect() (*sql.DB, error) {
	db, err := sql.Open("mysql", "root:root@/goschool")
	if err != nil {
		panic(err)
	}

	return db, nil
}
```

Selanjutnya kita akan mencoba menampilkan data pada table `students` di dalam fungsi `sqlQuery` :

```go
func sqlQuery() {
	// Check connection
	db, err := connect()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer db.Close()
	
	// Get data based on id student
	var id = 1
	rows, err := db.Query("select fullname, age, batch from students where id= ?", id)

	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer rows.Close()
	
	// Menampung data dari database ke dalam struct
	var result []Student
	for rows.Next() {
		var each = Student{}
		if err := rows.Scan(&each.Fullname, &each.Age, &each.Batch); err != nil {
			log.Fatal(err)
		}
		result = append(result, each)
	}
	
	// Menampilkan data
	for _, value := range result {
		fmt.Println(value.Fullname)
		fmt.Println(value.Age)
		fmt.Println(value.Batch)
	}
}
```

Kode lengkapnya akan menjadi seperti di bawah ini:

```go
package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

type Student struct {
	ID       int
	Fullname string
	Age      int
	Batch    string
}

func connect() (*sql.DB, error) {
	db, err := sql.Open("mysql", "root:root@/goschool")
	if err != nil {
		panic(err)
	}

	return db, nil
}

func sqlQuery() {
	db, err := connect()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer db.Close()

	var id = 1
	rows, err := db.Query("select fullname, age, batch from students where id= ?", id)

	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer rows.Close()

	var result []Student
	for rows.Next() {
		var each = Student{}
		if err := rows.Scan(&each.Fullname, &each.Age, &each.Batch); err != nil {
			log.Fatal(err)
		}
		result = append(result, each)
	}

	for _, value := range result {
		fmt.Println(value.Fullname)
		fmt.Println(value.Age)
		fmt.Println(value.Batch)
	}
}

func main() {
	sqlQuery()
}
```

Jika program di atas kita jalanka maka akan terlihat output program seperti berikut ini:

![Data yang diambil dari database](/files/-MTaQ4VahKwc7iDYzHGj)

### Membaca 1 Record Data Menggunakan Method `QueryRow()` <a href="#a564-membaca-1-record-data-menggunakan-method-queryrow" id="a564-membaca-1-record-data-menggunakan-method-queryrow"></a>

Jika kita membutuhkan 1 record data, kita bisa menggunakan method `QueryRow` yang lebih singkat secara kode seperti berikut ini:

```go
package main

import (
	"database/sql"
	"fmt"

	_ "github.com/go-sql-driver/mysql"
)

type Student struct {
	ID       int
	Fullname string
	Age      int
	Batch    string
}

func connect() (*sql.DB, error) {
	db, err := sql.Open("mysql", "root:root@/goschool")
	if err != nil {
		panic(err)
	}

	return db, nil
}

func sqlQuery() {
	db, err := connect()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer db.Close()

	var id = 1
	var student = Student{}
	err = db.QueryRow("select fullname, age, batch from students where id= ?", id).
		Scan(&student.Fullname, &student.Age, &student.Batch)

	if err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Println(student.Fullname)
	fmt.Println(student.Age)
	fmt.Println(student.Batch)
}

func main() {
	sqlQuery()
}
```

![Data yang diambil dari database](/files/-MTaSCXPxHDakoCVjw88)

### INSERT, UPDATE, dan DELETE

Untuk melakukan proses `INSERT` , `UPDATE` , dan `DELETE` kita bisa menggunakan fungsi `exec` karena fungsi ini jika dijalankan tidak akan mengembalikan data row pada database.

```go
package main

import (
	"database/sql"
	"fmt"

	_ "github.com/go-sql-driver/mysql"
)

type Student struct {
	ID       int
	Fullname string
	Age      int
	Batch    string
}

func connect() (*sql.DB, error) {
	db, err := sql.Open("mysql", "root:root@/goschool")
	if err != nil {
		panic(err)
	}

	return db, nil
}

func sqlQuery() {
	db, err := connect()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer db.Close()

	_, err = db.Exec("insert into students values (?, ?, ?, ?)", 5, "David Winalda", 26, "Clever")
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println("insert data success!")

	_, err = db.Exec("update students set age = ? where id = ?", 27, 4)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println("update data success!")

	_, err = db.Exec("delete from students where id = ?", 2)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println("delete data success!")
}

func main() {
	sqlQuery()
}
```

Jika program di atas dijalankan maka akan menampilkan output berikut ini:

![Menjalankan query menggunakan fungsi Exec](/files/-MTaVPFjqoO5UdPxJtj5)
