我如何根据不可预测的 db.Query() 创建新结构?

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

我在 table 的 db.query() 到 return 列中使用 SELECT *。通常,我会将 fmt.Scan() 行放入预先声明的 struct{} 中以进行进一步操作,但在这种情况下, table 列经常更改,因此我无法使用声明的 struct{} 作为我的 Scan().

的一部分

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

任何指点将不胜感激。

您可以从生成的行集中获取列名并为扫描准备切片。

示例(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)
        }
    }
}

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