# 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)
}
```