如何从一个不可预测的db.Query()中创建一个新的结构体?

huangapple go评论72阅读模式
英文:

How could I create a new struct from an unpredictable db.Query()?

问题

我正在使用db.query()中的SELECT *来返回表中的列。通常情况下,我会使用fmt.Scan()将行扫描到预先声明的struct{}中以进行进一步操作,但在这种情况下,表的列经常变化,所以我不能在Scan()中使用已声明的struct{}

我一直在努力弄清楚如何根据db.query()的列结果动态构建一个struct{},然后可以在Scan()中使用它。我已经阅读了一些关于reflect的内容,但我很难确定这是否适合我的用例,或者我是否需要考虑其他方法。

非常感谢任何指导。

英文:

I'm using SELECT * in a db.query() to return columns from a table. Typically, I would fmt.Scan() the rows into a pre-declared struct{} for further manipulation, but in this case, the table columns change frequently so I'm not able to use a declared struct{} as part of my Scan().

I've been struggling to figure out how I might dynamically build a struct{} based on the column results of the db.query() which I could subsequently call on the use of for Scan(). I've read a little about reflect but I'm struggling to determine if this is right for my use-case or if I might have to think about something else.

Any pointers would be greatly appreciated.

答案1

得分: 1

你可以从结果行集中获取列名,并为扫描准备一个切片。

示例(https://go.dev/play/p/ilYmEIWBG5S):

package main

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

	"github.com/DATA-DOG/go-sqlmock"
)

func main() {
	// 模拟数据库
	db, mock, err := sqlmock.New()
	if err != nil {
		log.Fatal(err)
	}

	columns := []string{"id", "status"}

	mock.ExpectQuery("SELECT \\* FROM table").
		WillReturnRows(sqlmock.NewRows(columns).AddRow(1, "ok"))

	// 实际代码
	rows, err := db.Query("SELECT * FROM table")
	if err != nil {
		log.Fatal(err)
	}

	cols, err := rows.Columns()
	if err != nil {
		log.Fatal(err)
	}

	data := make([]interface{}, len(cols))
	strs := make([]sql.NullString, len(cols))
	for i := range data {
		data[i] = &strs[i]
	}

	for rows.Next() {
		if err := rows.Scan(data...); err != nil {
			log.Fatal(err)
		}
		for i, d := range data {
			fmt.Printf("%s = %+v\n", cols[i], d)
		}
	}
}

此示例将所有列读入字符串。要检测列类型,可以使用rows.ColumnTypes方法。

英文:

you can get column names from resulting rowset and prepare a slice for the scan.

Example (https://go.dev/play/p/ilYmEIWBG5S) :

package main

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

	"github.com/DATA-DOG/go-sqlmock"
)

func main() {
	// mock db
	db, mock, err := sqlmock.New()
	if err != nil {
		log.Fatal(err)
	}

	columns := []string{"id", "status"}

	mock.ExpectQuery("SELECT \\* FROM table").
		WillReturnRows(sqlmock.NewRows(columns).AddRow(1, "ok"))

	// actual code
	rows, err := db.Query("SELECT * FROM table")
	if err != nil {
		log.Fatal(err)
	}

	cols, err := rows.Columns()
	if err != nil {
		log.Fatal(err)
	}

	data := make([]interface{}, len(cols))
	strs := make([]sql.NullString, len(cols))
	for i := range data {
		data[i] = &strs[i]
	}

	for rows.Next() {
		if err := rows.Scan(data...); err != nil {
			log.Fatal(err)
		}
		for i, d := range data {
			fmt.Printf("%s = %+v\n", cols[i], d)
		}
	}
}

This example reads all columns into strings. To detect column type one can use rows.ColumnTypes method.

huangapple
  • 本文由 发表于 2022年1月31日 05:16:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/70919007.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定