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