为了账号安全,请及时绑定邮箱和手机立即绑定

当我在 db(此处为 postgres)中的结构未知时,如何检索 GoLang 数据库/sql

当我在 db(此处为 postgres)中的结构未知时,如何检索 GoLang 数据库/sql

Go
繁星coding 2022-06-01 17:52:23
我使用 github.com/lib/pq 将 Go 与 PostgreSQL 一起使用,并且在我的结构已知时能够成功获取记录。现在我的查询是当我的结构动态变化时如何获取记录?通过rows.columns我可以获取列名,但是您能帮我获取所有行的这些列的值吗?我引用了@Luke 回答的这个链接,不过,这里的人已经定义了一个结构。 是否可以使用 GoLang 数据库/sql 按名称检索列值type Person struct {    Id int    Name string}同时,我没有固定的结构,所以我将如何遍历所有列,对所有行再次进行迭代。我的方法是先用一个指针循环遍历所有列,然后再循环遍历下一行。仍然无法对此进行编码,请您帮我解决这个问题,例如如何继续并获取值。
查看完整描述

3 回答

?
慕尼黑8549860

TA贡献1818条经验 获得超11个赞

由于您事先不知道结构,您可以将行作为空接口的二维切片返回。但是,要使行扫描起作用,您需要将值预分配给适当的类型,为此您可以使用ColumnTypes方法和reflect包。请记住,并非每个驱动程序都提供对列类型的访问,因此请确保您使用的驱动程序提供。


rows, err := db.Query("select * from foobar")

if err != nil {

    return err

}

defer rows.Close()


// get column type info

columnTypes, err := rows.ColumnTypes()

if err != nil {

    return err

}


// used for allocation & dereferencing

rowValues := make([]reflect.Value, len(columnTypes))

for i := 0; i < len(columnTypes); i++ {

    // allocate reflect.Value representing a **T value

    rowValues[i] = reflect.New(reflect.PtrTo(columnTypes[i].ScanType()))

}


resultList := [][]interface{}{}

for rows.Next() {

    // initially will hold pointers for Scan, after scanning the

    // pointers will be dereferenced so that the slice holds actual values

    rowResult := make([]interface{}, len(columnTypes))

    for i := 0; i < len(columnTypes); i++ {

        // get the **T value from the reflect.Value

        rowResult[i] = rowValues[i].Interface()

    }


    // scan each column value into the corresponding **T value

    if err := rows.Scan(rowResult...); err != nil {

        return err

    }


    // dereference pointers

    for i := 0; i < len(rowValues); i++ {

        // first pointer deref to get reflect.Value representing a *T value,

        // if rv.IsNil it means column value was NULL

        if rv := rowValues[i].Elem(); rv.IsNil() {

            rowResult[i] = nil

        } else {

            // second deref to get reflect.Value representing the T value

            // and call Interface to get T value from the reflect.Value

            rowResult[i] = rv.Elem().Interface()

        }

    }


    resultList = append(resultList, rowResult)


}

if err := rows.Err(); err != nil {

    return err

}


fmt.Println(resultList)

分享

编辑

跟随由于您事先不知道结构,您可以将行作为空接口的二维切片返回。但是,要使行扫描起作用,您需要将值预分配给适当的类型,为此您可以使用ColumnTypes方法和reflect包。请记住,并非每个驱动程序都提供对列类型的访问,因此请确保您使用的驱动程序提供。


rows, err := db.Query("select * from foobar")

if err != nil {

    return err

}

defer rows.Close()


// get column type info

columnTypes, err := rows.ColumnTypes()

if err != nil {

    return err

}


// used for allocation & dereferencing

rowValues := make([]reflect.Value, len(columnTypes))

for i := 0; i < len(columnTypes); i++ {

    // allocate reflect.Value representing a **T value

    rowValues[i] = reflect.New(reflect.PtrTo(columnTypes[i].ScanType()))

}


resultList := [][]interface{}{}

for rows.Next() {

    // initially will hold pointers for Scan, after scanning the

    // pointers will be dereferenced so that the slice holds actual values

    rowResult := make([]interface{}, len(columnTypes))

    for i := 0; i < len(columnTypes); i++ {

        // get the **T value from the reflect.Value

        rowResult[i] = rowValues[i].Interface()

    }


    // scan each column value into the corresponding **T value

    if err := rows.Scan(rowResult...); err != nil {

        return err

    }


    // dereference pointers

    for i := 0; i < len(rowValues); i++ {

        // first pointer deref to get reflect.Value representing a *T value,

        // if rv.IsNil it means column value was NULL

        if rv := rowValues[i].Elem(); rv.IsNil() {

            rowResult[i] = nil

        } else {

            // second deref to get reflect.Value representing the T value

            // and call Interface to get T value from the reflect.Value

            rowResult[i] = rv.Elem().Interface()

        }

    }


    resultList = append(resultList, rowResult)


}

if err := rows.Err(); err != nil {

    return err

}


fmt.Println(resultList)


查看完整回答
反对 回复 2022-06-01
?
慕斯709654

TA贡献1840条经验 获得超5个赞

此函数在不知道列类型和计数的情况下打印查询结果。这是不使用包的先前答案的变体。reflect


func printQueryResult(db *sql.DB, query string) error {

    rows, err := db.Query(query)

    if err != nil {

        return fmt.Errorf("canot run query %s: %w", query, err)

    }

    defer rows.Close()


    cols, _ := rows.Columns()

    row := make([]interface{}, len(cols))

    rowPtr := make([]interface{}, len(cols))

    for i := range row {

        rowPtr[i] = &row[i]

    }

    fmt.Println(cols)

    for rows.Next() {

        err = rows.Scan(rowPtr...)

        if err != nil {

            fmt.Println("cannot scan row:", err)

        }

        fmt.Println(row...)

    }

    return rows.Err()

}

诀窍是rows.Scan可以将值扫描到*interface{},但您必须将其包装起来interface{}才能将其传递给Scanusing ...。


查看完整回答
反对 回复 2022-06-01
?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

此函数在不知道列类型和计数的情况下打印查询结果。这是不使用包的先前答案的变体。reflect


func printQueryResult(db *sql.DB, query string) error {

    rows, err := db.Query(query)

    if err != nil {

        return fmt.Errorf("canot run query %s: %w", query, err)

    }

    defer rows.Close()


    cols, _ := rows.Columns()

    row := make([]interface{}, len(cols))

    rowPtr := make([]interface{}, len(cols))

    for i := range row {

        rowPtr[i] = &row[i]

    }

    fmt.Println(cols)

    for rows.Next() {

        err = rows.Scan(rowPtr...)

        if err != nil {

            fmt.Println("cannot scan row:", err)

        }

        fmt.Println(row...)

    }

    return rows.Err()

}

诀窍是rows.Scan可以将值扫描到*interface{},但您必须将其包装起来interface{}才能将其传递给Scanusing ...。


查看完整回答
反对 回复 2022-06-01
  • 3 回答
  • 0 关注
  • 98 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信