---
# System prepended metadata

title: Day28 Golang MySQL 基本操作 CRUD

---

# Day28 Golang MySQL 基本操作 CRUD


## 資料庫CRUD基本操作
`CRUD`單字意思為`粗魯的`，是`四種對 row 操作`的頭字詞單字縮寫:Create、Read、Update、Delete  

#### 【Insert】插入
```go
_, err := db.Exec("INSERT INTO `school`.`teacher`(`name`, `age`) VALUES ('Tiger' , 28)")
```

也可以使用佔位符（Placeholder ~~直譯就是`地主`啦！~~）來當作臨時變數。  
不過每個RDBMS的佔位符不一定相同，在MySQL是以 `?` 當作佔位符號。

```go
_, err := db.Exec("INSERT INTO `school`.`teacher`(`name` , `age`) VALUES (? , ?)", teacherName, teacherAge)
```

```go
func main(){
	insertTeacher("Tom", 51)
}

func insertTeacher(teacherName string, teacherAge int) {
	_, err := db.Exec("INSERT INTO `school`.`teacher`(`name` , `age`) VALUES (? , ?)", teacherName, teacherAge)
	...
}
```

```go
func insertStudent(studentName string) {
	rs, err := db.Exec("INSERT INTO `school`.`student`(`name`) VALUES (?)", studentName)
	if err != nil {
		log.Println(err)
	}

	rowCount, err := rs.RowsAffected()
	rowId, err := rs.LastInsertId() // 資料表中有Auto_Increment欄位才起作用，回傳剛剛新增的那筆資料ID

	if err != nil {
		log.Fatalln(err)
	}
	fmt.Printf("新增 %d 筆資料，id = %d \n", rowCount, rowId)
}
```

#### 【Select】選擇、查詢

用Select選擇`name`跟`age` 欄位來作印出。  


```go
rows, err := db.Query("SELECT `name`, `age` FROM `school`.`teacher`")
// rows, err := db.Query("SELECT * FROM `school`.`teacher`") // 也可以使用`Select *`選取全部欄位。
```

```go
for rows.Next() { // rows.Next() 前往下一個項目。如果成功（還有下一項的話）返回True、失敗（沒有下一項可讀）則返回False
		var tName string	//兩個欄位，依SELECT的順序用兩個變數來接
		var tAge int
	err = rows.Scan(&tName, &tAge) // 掃描後存進變數中
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Printf("%q %d\n", tName, tAge) // %q:quoted 用引號包起字串
}
defer rows.Close() // 當完整迭代rows.Next()完後會自動關閉rows，但以防萬一 最後記得要關閉rows 。
```

使用`條件Where` 語法來查詢年紀超過age的老師  

```go
func queryTeacherByAge(age int) {
	rows, err := db.Query("SELECT `name`, `age` FROM `school`.`teacher` WHERE `age` > ?;", age)
    ...
```

`db.Query`回傳符合結果的多筆資料`rows`，  
`db.QueryRow`用在確定只有一筆資料`row`回傳的時候。  

#### 【Update】更新

更新名字為name的老師的年齡為age  

```go
func updateTeacherAge(teacherName string, age int) {
	_, err := db.Exec("UPDATE `school`.`teacher` SET `age`= ? WHERE `name` = ?;", age, teacherName)
```

#### 【Delete】刪除

刪除名字為name的老師的資料列  

```go
func deleteTeacher(teacherName string) {
	_, err := db.Exec("DELETE FROM `school`.`teacher` WHERE `name` = ?;", teacherName)
    ...
```

> 在MySQL中，`INSERT` 可以沒有 `INTO`，但是 `DELETE` 不能沒有 `FROM`  

## 常用SQL函式

因為這些用法是SQL函式，關鍵字後必須加上`小括號()`  

#### 【Count】筆數

年紀資料不為`null`的老師總數  

```go
func numOfTeacher() {
	row := db.QueryRow("SELECT COUNT(`age`) FROM `school`.`teacher`;")
	var count int
	row.Scan(&count)
	fmt.Println(count)
}
```

#### 【Max, Min】最大最小值

查詢年紀最大的的老師  

```go
func oldestAge() {
	row := db.QueryRow("SELECT MAX(`age`) FROM `school`.`teacher`;")
	
	var tAge int
	row.Scan(&tAge)
	fmt.Println("老師年紀最大為:", tAge)
}
```

相反，用`MIN`則查詢年紀最小的老師。  

也可以使用`ORDER BY DESC`, `Limit`來查詢年紀最大者。  
```go
func oldestTeacher() {
	row := db.QueryRow("SELECT `name`, `age` FROM `school`.`teacher` ORDER BY `age` DESC Limit 1 ;")

	var tName string
	var tAge int
	row.Scan(&tName, &tAge)
	
	fmt.Println(tName, tAge)
}
```

#### 【Sum】加總

回傳老師們年紀的加總。  

```go
func SumOfTeachersAge() {
	row := db.QueryRow("SELECT SUM(`age`) FROM `school`.`teacher`;")
	var sum int
	row.Scan(&sum)
	fmt.Println(sum)
}
```
