_SELECT *
_を使用して、データベーステーブルの行をcsvファイルにダンプするGoプログラムを作成します。
Goは優れた sql および csv APIを提供しますが、csv
は文字列の配列とScan
のRows
メソッドを必要としますタイプに従ってフィールドを「埋める」。私は以前にテーブルを知らなかったので、列がいくつあるのか、そしてそれらの型が何なのか分かりません。
Goでの私の最初のプログラムなので、少し苦労しています。
Rows
インスタンスの列を_[]string
_に読み込むにはどうすればよいですか?それは「正しい」方法ですか?
ありがとう!
[〜#〜] update [〜#〜]
私はまだパラメーターに苦労しています。これが私のコードです。今のところ、panic
を返す代わりにerror
を使用していますが、後で変更します。私のテストでは、クエリ結果と_os.Stdout
_を渡します。
_func dumpTable(rows *sql.Rows, out io.Writer) error {
colNames, err := rows.Columns()
if err != nil {
panic(err)
}
if rows.Next() {
writer := csv.NewWriter(out)
writer.Comma = '\t'
cols := make([]string, len(colNames))
processRow := func() {
err := rows.Scan(cols...)
if err != nil {
panic(err)
}
writer.Write(cols)
}
processRow()
for rows.Next() {
processRow()
}
writer.Flush()
}
return nil
}
_
このために、cannot use cols (type []string) as type []interface {} in function argument
を取得します(writer.Write(cols)
行で)。
次にテストしました
_ readCols := make([]interface{}, len(colNames))
writeCols := make([]string, len(colNames))
processRow := func() {
err := rows.Scan(readCols...)
if err != nil {
panic(err)
}
// ... CONVERSION?
writer.Write(writeCols)
}
_
_panic: sql: Scan error on column index 0: destination not a pointer
_につながります。
更新2
私は独自に ANisus 'ソリューションに到着しました。これは私が今使用しているコードです。
_func dumpTable(rows *sql.Rows, out io.Writer) error {
colNames, err := rows.Columns()
if err != nil {
panic(err)
}
writer := csv.NewWriter(out)
writer.Comma = '\t'
readCols := make([]interface{}, len(colNames))
writeCols := make([]string, len(colNames))
for i, _ := range writeCols {
readCols[i] = &writeCols[i]
}
for rows.Next() {
err := rows.Scan(readCols...)
if err != nil {
panic(err)
}
writer.Write(writeCols)
}
if err = rows.Err(); err != nil {
panic(err)
}
writer.Flush()
return nil
}
_
値を直接Scan
に[]string
にするには、文字列スライスの各文字列を指す[]interface{}
スライスを作成する必要があります。
ここに、MySQLの実例があります(設定に合わせてsql.Open
-コマンドを変更するだけです):
package main
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"database/sql"
)
func main() {
db, err := sql.Open("mysql", "user:pass@tcp(localhost:3306)/test?charset=utf8")
defer db.Close()
if err != nil {
fmt.Println("Failed to connect", err)
return
}
rows, err := db.Query(`SELECT 'one' col1, 'two' col2, 3 col3, NULL col4`)
if err != nil {
fmt.Println("Failed to run query", err)
return
}
cols, err := rows.Columns()
if err != nil {
fmt.Println("Failed to get columns", err)
return
}
// Result is your slice string.
rawResult := make([][]byte, len(cols))
result := make([]string, len(cols))
dest := make([]interface{}, len(cols)) // A temporary interface{} slice
for i, _ := range rawResult {
dest[i] = &rawResult[i] // Put pointers to each string in the interface slice
}
for rows.Next() {
err = rows.Scan(dest...)
if err != nil {
fmt.Println("Failed to scan row", err)
return
}
for i, raw := range rawResult {
if raw == nil {
result[i] = "\\N"
} else {
result[i] = string(raw)
}
}
fmt.Printf("%#v\n", result)
}
}
列数(および名前)を取得するには、Columns()関数を使用します
http://golang.org/pkg/database/sql/#Rows.Columns
また、csvは文字列のみであるため、[] byte型をScannerのdest型として使用します。 docuによると:
引数のタイプが* [] byteの場合、スキャンはその引数に対応するデータのコピーを保存します。コピーは呼び出し元が所有し、無期限に変更および保持できます。
データは実際の型に変換されません。そして、この[]バイトから文字列に変換できます。
テーブルが基本型(string、[] byte、nil、int(s)、float(s)、bool)のみを使用していることが確実な場合、destとして文字列を直接渡すことができます。
しかし、配列、列挙などのような他の型を使用する場合、データは文字列に変換できません。ただし、これはドライバーがこのタイプを処理する方法にも依存します。 (数か月前の例として、postgresドライバーは配列を処理できなかったため、自分で変換する必要がある場所で常に[]バイトを返しました)
代わりにこれを行うことができませんでしたか?以下に簡略化。
var tmpErrors string
_ = row.Scan(&tmpErrors)
actualVarHere := strings.Split(tmpErrors, "\n")
表示されない問題やパフォーマンスの問題はありますか?
次のコードは要件をきれいに示しています。このコードは https://Gist.github.com/hygull/645c3dc39c69b6b69c06f5ea9deee41f で入手できます。テーブルデータも提供されています。
/**
{
"created_on": "26 may 2017",
"todos": [
"go get github.com/go-sql-driver/mysql"
],
"aim": "Reading fname column into []string(slice of strings)"
}
*/
/*
mysql> select * from users;
+----+-----------+----------+----------+-------------------------------+--------------+
| id | fname | lname | uname | email | contact |
+----+-----------+----------+----------+-------------------------------+--------------+
| 1 | Rishikesh | Agrawani | hygull | [email protected] | 917353787704 |
| 2 | Sandeep | E | sandeep | [email protected] | 919739040038 |
| 3 | Darshan | Sidar | darshan | [email protected] | 917996917565 |
| 4 | Surendra | Prajapat | surendra | [email protected] | 918385894407 |
| 5 | Mukesh | Jakhar | mukesh | [email protected] | 919772254140 |
+----+-----------+----------+----------+-------------------------------+--------------+
5 rows in set (0.00 sec)
mysql>
*/
package main
import "fmt"
import "log"
import (
_"github.com/go-sql-driver/mysql"
"database/sql"
)
func main() {
// db, err := sql.Open("mysql", "<username>:<password>@tcp(127.0.0.1:<port>)/<dbname>?charset=utf8" )
db, err := sql.Open("mysql", "hygull:admin@67@tcp(127.0.0.1:3306)/practice_db?charset=utf8")
if err != nil {
log.Fatal(err)
}
rows, err := db.Query("select fname from users")
if err != nil {
log.Fatal(err)
}
firstnames:=[]string{}
for rows.Next() {
var fname string
rows.Scan(&fname)
firstnames = append(firstnames, fname)
}
fmt.Println(firstnames)
db.Close()
}
/*
[Rishikesh Sandeep Darshan Surendra Mukesh]
*/