如何从数据库行创建Golang地图?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (3)
  • 关注 (0)
  • 查看 (16)

基本上,在执行查询之后,我希望获取结果行并生成一个[]map[string]interface{},但是我不知道如何使用API来实现这一点,因为Rows.Scan()函数需要与请求的列数(可能还包括类型)匹配的特定数量的参数才能正确获取数据。

再次,想泛化这个调用,并接受任何查询并将其转换为[]map[string]interface{},其中映射包含映射到该行值的列名。

这可能非常低效,我计划稍后更改结构,以便interface{}是单个数据点的结构。

我如何使用数据库/SQL包,或者如果必要的话使用数据库/SQL/驱动程序包?

提问于
用户回答回答于

可以创建一个结构来维护映射键到[]interface{} slice。通过这样做,不需要创建预定义的结构。例如:

IDOrder: 0
IsClose: 1
IsConfirm: 2
IDUser: 3

然后,可以这样使用它:

  // create a fieldbinding object.
  var fArr []string
  fb := fieldbinding.NewFieldBinding()

  if fArr, err = rs.Columns(); err != nil {
    return nil, err
  }

  fb.PutFields(fArr)

  //
  outArr := []interface{}{}

  for rs.Next() {
    if err := rs.Scan(fb.GetFieldPtrArr()...); err != nil {
      return nil, err
    }

    fmt.Printf("Row: %v, %v, %v, %s\n", fb.Get("IDOrder"), fb.Get("IsConfirm"), fb.Get("IDUser"), fb.Get("Created"))
    outArr = append(outArr, fb.GetFieldArr())
  }

样本输出:

Row: 1, 1, 1, 2016-07-15 10:39:37 +0000 UTC
Row: 2, 1, 11, 2016-07-15 10:42:04 +0000 UTC
Row: 3, 1, 10, 2016-07-15 10:46:20 +0000 UTC
SampleQuery: [{"Created":"2016-07-15T10:39:37Z","IDOrder":1,"IDUser":1,"IsClose":0,"IsConfirm":1},{"Created":"2016-07-15T10:42:04Z","IDOrder":2,"IDUser":11,"IsClose":0,"IsConfirm":1},{"Created":"2016-07-15T10:46:20Z","IDOrder":3,"IDUser":10,"IsClose":0,"IsConfirm":1}]

请参阅下面的完整示例或字段绑定:

main.go

package main

import (
    "bytes"
    "database/sql"
    "encoding/json"
    "fmt"
)

import (
    _ "github.com/go-sql-driver/mysql"
    "github.com/junhsieh/goexamples/fieldbinding/fieldbinding"
)

var (
    db *sql.DB
)

// Table definition
// CREATE TABLE `salorder` (
//   `IDOrder` int(10) unsigned NOT NULL AUTO_INCREMENT,
//   `IsClose` tinyint(4) NOT NULL,
//   `IsConfirm` tinyint(4) NOT NULL,
//   `IDUser` int(11) NOT NULL,
//   `Created` datetime NOT NULL,
//   `Changed` datetime NOT NULL,
//   PRIMARY KEY (`IDOrder`),
//   KEY `IsClose` (`IsClose`)
// ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

func main() {
    var err error

    // starting database server
    db, err = sql.Open("mysql", "Username:Password@tcp(Host:Port)/DBName?parseTime=true")

    if err != nil {
        panic(err.Error()) // Just for example purpose. You should use proper error handling instead of panic
    }

    defer db.Close()

    // SampleQuery
    if v, err := SampleQuery(); err != nil {
        fmt.Printf("%s\n", err.Error())
    } else {
        var b bytes.Buffer

        if err := json.NewEncoder(&b).Encode(v); err != nil {
            fmt.Printf("SampleQuery: %v\n", err.Error())
        }

        fmt.Printf("SampleQuery: %v\n", b.String())
    }
}

func SampleQuery() ([]interface{}, error) {
    param := []interface{}{}

    param = append(param, 1)

    sql := "SELECT "
    sql += "  SalOrder.IDOrder "
    sql += ", SalOrder.IsClose "
    sql += ", SalOrder.IsConfirm "
    sql += ", SalOrder.IDUser "
    sql += ", SalOrder.Created "
    sql += "FROM SalOrder "
    sql += "WHERE "
    sql += "IsConfirm = ? "
    sql += "ORDER BY SalOrder.IDOrder ASC "

    rs, err := db.Query(sql, param...)

    if err != nil {
        return nil, err
    }

    defer rs.Close()

    // create a fieldbinding object.
    var fArr []string
    fb := fieldbinding.NewFieldBinding()

    if fArr, err = rs.Columns(); err != nil {
        return nil, err
    }

    fb.PutFields(fArr)

    //
    outArr := []interface{}{}

    for rs.Next() {
        if err := rs.Scan(fb.GetFieldPtrArr()...); err != nil {
            return nil, err
        }

        fmt.Printf("Row: %v, %v, %v, %s\n", fb.Get("IDOrder"), fb.Get("IsConfirm"), fb.Get("IDUser"), fb.Get("Created"))
        outArr = append(outArr, fb.GetFieldArr())
    }

    if err := rs.Err(); err != nil {
        return nil, err
    }

    return outArr, nil
}

现场绑定包:

package fieldbinding

import (
    "sync"
)

// NewFieldBinding ...
func NewFieldBinding() *FieldBinding {
    return &FieldBinding{}
}

// FieldBinding is deisgned for SQL rows.Scan() query.
type FieldBinding struct {
    sync.RWMutex // embedded.  see http://golang.org/ref/spec#Struct_types
    FieldArr     []interface{}
    FieldPtrArr  []interface{}
    FieldCount   int64
    MapFieldToID map[string]int64
}

func (fb *FieldBinding) put(k string, v int64) {
    fb.Lock()
    defer fb.Unlock()
    fb.MapFieldToID[k] = v
}

// Get ...
func (fb *FieldBinding) Get(k string) interface{} {
    fb.RLock()
    defer fb.RUnlock()
    // TODO: check map key exist and fb.FieldArr boundary.
    return fb.FieldArr[fb.MapFieldToID[k]]
}

// PutFields ...
func (fb *FieldBinding) PutFields(fArr []string) {
    fCount := len(fArr)
    fb.FieldArr = make([]interface{}, fCount)
    fb.FieldPtrArr = make([]interface{}, fCount)
    fb.MapFieldToID = make(map[string]int64, fCount)

    for k, v := range fArr {
        fb.FieldPtrArr[k] = &fb.FieldArr[k]
        fb.put(v, int64(k))
    }
}

// GetFieldPtrArr ...
func (fb *FieldBinding) GetFieldPtrArr() []interface{} {
    return fb.FieldPtrArr
}

// GetFieldArr ...
func (fb *FieldBinding) GetFieldArr() map[string]interface{} {
    m := make(map[string]interface{}, fb.FieldCount)

    for k, v := range fb.MapFieldToID {
        m[k] = fb.FieldArr[v]
    }

    return m
}

热门问答

域名注册时写了企业,可以转为个人的吗?

滑稽园扛把子

Swoole · PHP开发工程师 (已认证)

As a PHP Developer
推荐
可以的,操作如下 登录控制台 登录 腾讯云控制台。 选择 “云产品 > 域名与网站 > 域名注册”,进入 “域名服务” 页面,查看已购买的所有域名信息。 修改/过户域名信息 在需要修改域名信息的域名行中,单击【更多】,选择【域名信息修改】。如下图所示: 也可直接单击需要修改域名信...... 展开详请

如何按照上传时间顺序,获取cos bucket 中的object信息?

波斯狗儿对象存储产品经理
推荐
对象存储是 KV 有序存储,只能按对象键 UTF-8 字符顺序排。详细了解对象的概念:https://cloud.tencent.com/document/product/436/13324 如果需要按时间列表,需要在上传时就指定好路径,这样列表的时候也是按顺序的。比如 pho...... 展开详请

云开发环境和开发者自己的服务器能连通吗?

李成熙heyli

腾讯 · 高级工程师 (已认证)

腾讯高级工程师,专注于工程化及性能优化。 https://github.com/lcxfs1991
可以的请参考这份教程: https://github.com/TencentCloudBase/mp-book/blob/master/guide/readme.md#3-%E5%9C%A8%E8%87%AA%E5%B7%B1%E7%9A%84%E6%9C%8D%E5%8A%A1...... 展开详请

腾讯云 COS 怎么才能外链调用 m3u8 到别的网站播放?

滑稽园扛把子

Swoole · PHP开发工程师 (已认证)

As a PHP Developer
推荐
设置公有读私有写:当访问对象时,COS 读取到对象的权限为公有读,此时无论存储桶为何种权限,对象都可以被直接下载 设置步骤 登录 对象存储控制台,选择左侧菜单栏【存储桶列表】,进入存储桶列表页面。单击需要修改对象权限的对应存储桶,进入存储桶。 📷 找到需要设置权限的对象(如 e...... 展开详请

云通信IM 可以发送语音消息吗?

应兆康腾讯云+校园合伙人
可以的哦,在云通信IM的文档中有写 消息类型(文本,图片,语音,表情等自定义消息): 文本:最大 1~2k 字节(支持透传特殊字符); 图片:原图/缩略图/大图(支持格式:png/gif/jpeg/jpg/webp); 语音:异步语音消息(语音支持暂无上限); 表情等自定义消息...... 展开详请

Ubuntu搭建的WordPress如何修改php.ini?

滑稽园扛把子

Swoole · PHP开发工程师 (已认证)

As a PHP Developer
推荐
php新手很多不知道怎么查配置文件在哪,这里提供一个很简单的方法 使用 php -i 命令可以打印php的详细信息,可以把这堆东西输出一下 php -i > outputphp.txt,结合 grep 查找命令 php -i| grep php.ini 打印结果如下 Config...... 展开详请

所属标签

扫码关注云+社区